<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>IAMOTI</title>
        <link>https://paragraph.com/@iamoti</link>
        <description>undefined</description>
        <lastBuildDate>Mon, 06 Apr 2026 05:25:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>IAMOTI</title>
            <url>https://storage.googleapis.com/papyrus_images/179315974e253d8a28a0debeef4411fa2778035a8d5ae7f1b3376213afee42a9.jpg</url>
            <link>https://paragraph.com/@iamoti</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Merkle Trees and Efficient Airdrop Distribution System]]></title>
            <link>https://paragraph.com/@iamoti/merkle-trees-and-efficient-airdrop-distribution-system</link>
            <guid>lIUXAyfmxvDwkjcoWq2S</guid>
            <pubDate>Wed, 02 Oct 2024 00:36:23 GMT</pubDate>
            <description><![CDATA[Welcome Back! if this is your first time Welcome … In today&apos;s article, we dive deeper into one of the most fascinating data structure/ cryptographic proof I&apos;ve become obsessed with. I think you&apos;ll find it interesting too! From the title, you already know that we will be talking about Merkle Trees and Merkle Proofs, and how they are used in an airdrop distribution system. We are going to explore:What is a Merkle Tree?How does a Merkle Proof work?How are Merkle Trees applied in a...]]></description>
            <content:encoded><![CDATA[<p><strong>Welcome Back! if this is your first time Welcome …</strong></p><p>In today&apos;s article, we dive deeper into one of the most fascinating data structure/ cryptographic proof I&apos;ve become obsessed with. I think you&apos;ll find it interesting too! From the title, you already know that we will be talking about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Merkle_tree"><strong>Merkle Trees</strong></a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5"><strong>Merkle Proofs</strong>,</a> and how they are used in an airdrop distribution system.</p><p>We are going to explore:</p><ul><li><p><strong>What is a Merkle Tree?</strong></p></li><li><p><strong>How does a Merkle Proof work?</strong></p></li><li><p><strong>How are Merkle Trees applied in an airdrop distribution system</strong></p></li></ul><h2 id="h-understanding-merkle-trees" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Understanding Merkle Trees</h2><p>A Merkle tree, also known as a hash tree, is a fundamental data structure used in cryptography and blockchain systems. It efficiently verifies the integrity of large datasets by breaking them down into smaller parts and hashing those parts repeatedly until a single root hash is formed. Each &quot;leaf&quot; in a Merkle tree represents a hash of a data block, while every &quot;parent&quot; node represents a hash of its child nodes&apos; combined hashes. This structure allows for efficient and secure verification since only part of the tree needs to be traversed to confirm data validity. Think of it as a sort of upside down tree. Let’s take a look at a basic example .</p><h3 id="h-example-of-a-basic-merkle-tree" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Example of a Basic Merkle Tree</h3><p>Let&apos;s take the example of four data blocks, which are labeled as <strong>Data Block 1</strong>, <strong>Data Block 2</strong>, <strong>Data Block 3</strong>, and <strong>Data Block 4</strong>.</p><ol><li><p>First, we hash each data block:</p><ul><li><p>Merkle Trees and Efficient Airdrop Distribution System</p></li><li><p>Hash of <strong>Data Block 2</strong> results in <strong>Hash 2</strong>.</p></li><li><p>Hash of <strong>Data Block 3</strong> results in <strong>Hash 3</strong>.</p></li><li><p>Hash of <strong>Data Block 4</strong> results in <strong>Hash 4</strong>.</p></li></ul></li><li><p>Then, we pair up adjacent hashes and combine them:</p><ul><li><p><strong>Hash 1</strong> and <strong>Hash 2</strong> are combined and hashed to form <strong>Hash 1-2</strong>.</p></li><li><p><strong>Hash 3</strong> and <strong>Hash 4</strong> are combined and hashed to form <strong>Hash 3-4</strong>.</p></li></ul></li><li><p>Finally, <strong>Hash 1-2</strong> and <strong>Hash 3-4</strong> are combined and hashed to create the <strong>Root Hash</strong>, which is the top node of the tree.</p></li></ol><p>Here’s the Merkle tree visualization:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/44bce586146eb56f505a837a5c76e104b077ab3d62306e8b9738869e30b5697e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>In this diagram:</p><ul><li><p>The <strong>Root Hash</strong> is at the top, which represents the combined hash of all data blocks.</p></li><li><p>Each intermediate node, such as <strong>Hash 1-2</strong> and <strong>Hash 3-4</strong>, is the hash of the concatenated hashes of the data blocks beneath it.</p></li><li><p>The leaf nodes (<strong>Data Block 1</strong> to <strong>Data Block 4</strong>) contain the actual data, which are hashed to create the tree.</p></li></ul><p>The advantage of this structure is that it allows for efficient verification of data. For example, if someone wants to verify the integrity of <strong>Data Block 1</strong>, they only need to know <strong>Hash 2</strong>, <strong>Hash 3-4</strong>, and the root hash. This reduces the amount of data needed for verification without requiring the entire dataset cool right ?.</p><h3 id="h-why-merkle-trees" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Why Merkle Trees ?</h3><p>You might be wondering, why use a Merkle tree, and why am I even writing this article? Well, the truth is, Merkle trees are a cornerstone in many verification and chain-link systems, from blockchain to version control systems like Git. Their primary strength is in ensuring data integrity while minimizing the amount of data stored and transferred.</p><p>In essence, a Merkle tree allows you to verify that a particular piece of data belongs to a larger dataset, without needing to store or transfer the entire dataset. This is especially useful for systems where efficiency and security are crucial, like blockchains (Bitcoin, Ethereum), decentralized applications, or even systems like <strong>AirDrop distribution</strong>, which we will dive into very soon.</p><p>But it&apos;s not just in blockchain. Ever wondered how <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects">Git keeps track</a> of all your file changes so efficiently? That’s right—<strong>Merkle trees</strong>. Git uses a Merkle-like structure to store commits, with each commit representing a snapshot of your project. When Linus Torvalds created Git, he probably wasn&apos;t thinking, &quot;I need a Merkle tree!&quot;—but that&apos;s exactly what Git ended up using. It helps Git keep track of every version of your code while ensuring that each commit can be verified for integrity.</p><p>And it&apos;s not just Git. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://bittorrent.org/beps/bep_0030.html"><strong>BitTorrent</strong></a>, the peer-to-peer file-sharing protocol, uses Merkle trees to efficiently verify the integrity of large files during download. By using small pieces of the file and their corresponding hashes, it ensures that a downloaded chunk matches the original without needing the entire file at once, making it a robust system for decentralized data transfer.</p><p>Even <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.allthingsdistributed.com/2007/10/amazons_dynamo.html"><strong>Amazon DynamoDB</strong></a>, a distributed database system, employs Merkle trees for replication and consistency. Dynamo uses them to compare data between replicas, ensuring that only differences are transferred, which saves bandwidth and accelerates data synchronization in distributed systems.</p><p>And hey, if Torvalds hadn’t built Git so well, we&apos;d probably still be using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Concurrent_Versions_System">CVS</a>—and nobody wants that! now let dive into how to use it in an airdrop system and see how the proof works</p><h3 id="h-designing-an-airdrop-distribution-system-with-merkle-tree" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Designing an Airdrop Distribution System with Merkle Tree</h3><p>In an airdrop system, a <strong>Merkle Tree</strong> allows us to keep the entire list of airdrop recipients and their respective token amounts <strong>off-chain</strong>. Instead of storing all the data on-chain, we only store a <strong>commitment</strong>—a sort of cryptographic <strong>fingerprint</strong> known as the <strong>Merkle Root</strong> (or root hash as discuss earlier)—on the blockchain.</p><p>Here’s how it works: when someone wants to claim their airdrop, they submit a <strong>proof</strong> (we will look into that shortly) that includes their address and claimable amount (e.g., 100 tokens). The contract will then verify this proof by comparing it with the on-chain <strong>Merkle Root</strong>. If the proof is valid, the contract confirms that the claim is legitimate and releases the tokens.</p><p>The beauty of this system is that it significantly reduces on-chain storage costs (so storing on the blockchain is expensive ) while maintaining secure and efficient verification of claims through the Merkle Tree structure.</p><h3 id="h-how-it-works" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How It Works:</h3><ul><li><p>All the tree construction happens <strong>off-chain</strong>.</p></li><li><p>The contract storage only contains the <strong>Merkle Root</strong> (the &quot;fingerprint&quot;).</p></li><li><p>The off-chain part includes building the <strong>Merkle Tree</strong> from a set of data, such as airdrop addresses and token amounts.</p></li></ul><p>At the bottom of our tree (the <strong>leaves</strong>), we have the actual data we care about:</p><ul><li><p>All the addresses eligible for the airdrop.</p></li><li><p>The corresponding token amounts for each address.</p></li></ul><p>In this example, we also include an <strong>index</strong> for each leaf, but I’ll explain that in a minute. For now, let’s focus on the basic chunks of data.</p><ol><li><p><strong>Hashing the Leaves</strong>:</p><p>We take each of these leaves (the address and amount) and hash them. This hashing can be done by concatenating the address, amount, and other values (e.g., the index). The key point is to stay consistent. Once we concatenate the values, we hash them—represented by <strong>H</strong>. The result is a <strong>256-bit hash</strong>.</p></li><li><p><strong>Hashing the Pairs</strong>:</p><p>After hashing each piece of data individually, we take each <strong>pair of hashes</strong> and combine them. We then hash the combined values together. This step is repeated at each level of the tree.</p></li><li><p><strong>Constructing the Root</strong>:</p><p>We continue combining and hashing pairs until we reach the top, resulting in the <strong>Merkle Root</strong>. This root is the fingerprint stored on-chain.</p></li></ol><p>As developers, we compute all of this <strong>off-chain</strong>—it might require some computation, but since it’s off-chain, gas fees aren’t a concern. After the Merkle Tree is constructed, we either:</p><ul><li><p>Deploy the contract with the <strong>Merkle Root</strong> stored within it, or</p></li><li><p>Use an administrative function to set the Merkle Root and write it into the contract.</p></li></ul><p>Once the Merkle Root is in the contract, the airdrop system is ready to verify claims.</p><p>Here’s a way to visualize the structure and flow of the Merkle tree for an airdrop system,</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/745c3c6c19ea97b23ed7639b00d6f0faa6cf8f2c29710336ce3d93ea78ad12b5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Before we implement the code let us take a sometime to talk about the way the proof works, that is how we know a particular data belongs to the tree</p><h3 id="h-how-does-this-work" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How Does This Work?</h3><p>At first glance, it might seem strange that a system based on <strong>Merkle Trees</strong> works with such minimal data, yet maintains a high level of security. You might wonder, &quot;How can I simply provide my data, a few additional hashes, and have the contract verify my claim without needing to see the full dataset?&quot;</p><p>The magic lies in how <strong>hash functions</strong> and <strong>Merkle Trees</strong> interact to create a secure proof of membership, even when most of the data is not directly provided to the smart contract.</p><h3 id="h-step-by-step-breakdown" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step-by-Step Breakdown:</h3><ol><li><p><strong>Merkle Tree Construction</strong>:</p><ul><li><p>A Merkle Tree is a binary tree where:</p><ul><li><p><strong>Leaves</strong> are the actual data (e.g., addresses and token amounts in an airdrop).</p></li><li><p><strong>Internal nodes</strong> are hashes derived from combining the hashes of their child nodes.</p></li><li><p>The <strong>Merkle Root</strong> at the top is the ultimate &quot;fingerprint&quot; of the entire dataset.</p></li></ul></li></ul><p>All the leaves at the bottom represent individual pieces of data (addresses and claim amounts). When the Merkle Tree is created off-chain, each leaf is hashed, and those hashes are combined in pairs, hashed again, until reaching the <strong>Merkle Root</strong>, which is stored in the contract.</p></li><li><p><strong>How Verification Works</strong>: When you want to claim your tokens, instead of submitting the entire dataset, you submit:</p><ul><li><p><strong>Your leaf data</strong> (address and claim amount).</p></li><li><p><strong>A Merkle Proof</strong>, which includes the <strong>sibling hashes</strong> along the path from your leaf to the root.</p></li></ul><p>The smart contract verifies the <strong>authenticity</strong> of your data by:</p><ul><li><p>Hashing your leaf data.</p></li><li><p>Using the sibling hashes to recreate the path up the Merkle Tree.</p></li><li><p>Once the contract computes the Merkle Root, it compares it to the stored root.</p></li></ul><p>If the roots match, your proof is valid, and the contract approves your claim.</p></li></ol><h3 id="h-proofs-and-tree-structure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Proofs and Tree Structure</h3><p>If we simply wanted to store a <strong>fingerprint</strong> of data on-chain, we could concatenate the entire dataset, hash it, and store the hash in the contract. However, this wouldn&apos;t allow us to produce <strong>Merkle Proofs</strong>.</p><p>Without a <strong>tree structure</strong>, you&apos;d need to provide all the other data alongside your own to verify it, which would be <strong>incredibly expensive</strong>. This is where <strong>Merkle Trees</strong> shine, allowing us to <strong>prove membership</strong> efficiently with only a fraction of the data.</p><h3 id="h-how-merkle-proofs-work" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How Merkle Proofs Work:</h3><p>To claim tokens, you need to provide the following data:</p><ol><li><p><strong>Your Leaf (Data)</strong>: This is your address and the token amount you&apos;re claiming. The contract hashes this data.</p></li><li><p><strong>Sibling Hashes</strong>: These are the hashes needed to compute the path from your leaf to the root.</p></li></ol><p>The contract performs the following steps:</p><ul><li><p>Hashes your data.</p></li><li><p>Uses sibling hashes to compute the next level&apos;s hash.</p></li><li><p>Repeats this process until it reaches the Merkle Root.</p></li><li><p>Compares the computed root with the stored root.</p></li></ul><p>If the computed root matches, the proof is valid.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/72b198aea006cd1e52098ba789e4613897b75e30f7451d7a0124fffe87c5f37d.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Proof Complexity: ( for my cs nerds)</p><p>For each proof of membership in the Merkle Tree, you need to provide one additional <strong>hash</strong> (sibling) per level of the tree. The beauty of this approach lies in the fact that the <strong>height of the tree is logarithmic</strong> in relation to the number of leaves.</p><p>For example:</p><ul><li><p>With 1 million data leaves, the tree has a height of 21.</p></li><li><p>If you increase the number of leaves to 1 billion (a 1000x increase), the tree’s height only grows to <strong>30 or 31</strong> levels.</p></li></ul><p>This logarithmic property means the <strong>proof complexity</strong> is very efficient. Even if the dataset grows massively, the height of the tree increases only slightly. The formula for proof complexity is <strong>O(log₂(n))</strong>, where <code>n</code> is the number of leaves.</p><p>Therefore, producing and verifying proofs is highly efficient, no matter how large the dataset is. The contract only needs to store <strong>one root</strong> (a 256-bit hash), even if the tree contains billions of items.</p><h3 id="h-why-the-system-is-secure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Why the System is Secure</h3><p>It seems almost too simple that I can provide just my leaf (address and amount) and a few sibling hashes, and the system will trust that my claim is legitimate. But the key lies in the properties of <strong>cryptographic hash functions</strong> and <strong>Merkle Trees</strong>. Here’s why this works securely:</p><h3 id="h-1-cryptographic-hash-functions-are-collision-resistant" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. <strong>Cryptographic Hash Functions are Collision-Resistant</strong>:</h3><p>A <strong>hash function</strong> is a one-way cryptographic algorithm that maps an input (of any size) to a fixed-size output, called a <strong>hash</strong>. Good hash functions, like <strong>SHA-256</strong>, have a few important properties:</p><ul><li><p><strong>Deterministic</strong>: The same input will always produce the same output.</p></li><li><p><strong>Irreversible</strong>: It is practically impossible to reverse-engineer the original input from its hash.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Collision_resistance"><strong>Collision-Resistant</strong></a>: It is incredibly difficult to find two different inputs that produce the same hash (a collision).</p></li></ul><p>Because of this, the hash function ensures that even the smallest change to the input data results in a completely different hash. For example, if I try to modify the amount I’m eligible to claim by even a single bit, the resulting hash will be wildly different from the correct hash.</p><h3 id="h-2-the-role-of-the-merkle-tree" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. <strong>The Role of the Merkle Tree</strong>:</h3><p>The structure of the Merkle Tree takes advantage of this collision resistance. Let’s say you try to manipulate your claim:</p><ul><li><p><strong>Step 1</strong>: You alter your address or claim amount. This change results in a completely different hash for your leaf.</p></li><li><p><strong>Step 2</strong>: You would then need to find a fake sibling hash that, when combined with your new leaf hash, still produces the same parent hash as before.</p></li><li><p><strong>Step 3</strong>: You continue this process all the way up the tree to the root.</p></li></ul><p>The challenge here is that you need to ensure each new hash at every level matches what the contract expects. But because hash functions are so sensitive to input changes, finding <strong>valid sibling hashes</strong> that would result in the same root is essentially impossible.</p><h3 id="h-3-impossibility-of-faking-proofs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. <strong>Impossibility of Faking Proofs</strong>:</h3><ul><li><p>If you manipulate any part of your data (e.g., increasing the amount of tokens you want to claim), the hash of your leaf changes.</p></li><li><p>This means you would need to invent fake hashes at every level of the tree to produce the correct root.</p></li><li><p>Due to the collision-resistant nature of hash functions, finding such a set of fake hashes would take an astronomically long time—far longer than the lifetime of the universe, using any current computational methods.</p></li></ul><p>Even though there are technically multiple inputs that could hash to the same output (due to the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.geeksforgeeks.org/discrete-mathematics-the-pigeonhole-principle/"><strong>pigeonhole principle</strong></a>), finding those collisions is <strong>computationally infeasible</strong> with modern hash functions like SHA-256 incase of the EVM Keccak256 . So, it’s effectively impossible to cheat the system.</p><hr><h2 id="h-implementing-a-merkle-tree-airdrop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Implementing a Merkle Tree Airdrop</h2><p>Let&apos;s walk through the process of implementing a Merkle tree-based airdrop system using Solidity and JavaScript.</p><h3 id="h-1-creating-the-merkle-tree" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. Creating the Merkle Tree</h3><p>First, we need to create our Merkle tree off-chain. Here&apos;s a JavaScript implementation using the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/merkle-tree">OpenZeppelin Merkle tree library</a>:</p><pre data-type="codeBlock" text="const { StandardMerkleTree } = require(&quot;@openzeppelin/merkle-tree&quot;);
const fs = require(&quot;fs&quot;);

const values = [
  [&quot;0x70997970C51812dc3A010C7d01b50e0d17dc79C8&quot;, &quot;0&quot;, &quot;10000000000000000000&quot;],
  [&quot;0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC&quot;, &quot;1&quot;, &quot;20000000000000000000&quot;],
  // ... more addresses and amounts ...
];

const tree = StandardMerkleTree.of(values, [&quot;address&quot;, &quot;uint256&quot;, &quot;uint256&quot;]);

console.log(&quot;Merkle Root:&quot;, tree.root);

fs.writeFileSync(&quot;tree.json&quot;, JSON.stringify(tree.dump(), null, 2), &quot;utf8&quot;);
"><code>const { StandardMerkleTree } <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"@openzeppelin/merkle-tree"</span>);
const fs <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

const values <span class="hljs-operator">=</span> [
  [<span class="hljs-string">"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"</span>, <span class="hljs-string">"0"</span>, <span class="hljs-string">"10000000000000000000"</span>],
  [<span class="hljs-string">"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"</span>, <span class="hljs-string">"1"</span>, <span class="hljs-string">"20000000000000000000"</span>],
  <span class="hljs-comment">// ... more addresses and amounts ...</span>
];

const tree <span class="hljs-operator">=</span> StandardMerkleTree.of(values, [<span class="hljs-string">"address"</span>, <span class="hljs-string">"uint256"</span>, <span class="hljs-string">"uint256"</span>]);

console.log(<span class="hljs-string">"Merkle Root:"</span>, tree.root);

fs.writeFileSync(<span class="hljs-string">"tree.json"</span>, JSON.stringify(tree.dump(), null, <span class="hljs-number">2</span>), <span class="hljs-string">"utf8"</span>);
</code></pre><p>This script creates a Merkle tree from a list of addresses, indices, and token amounts, then saves the tree structure to a JSON file.</p><h3 id="h-2-smart-contract-implementation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. Smart Contract Implementation</h3><p>Now, let&apos;s look at the Solidity contract that handles the airdrop claims:</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20} from &quot;@openzeppelin/contracts/token/ERC20/IERC20.sol&quot;;
import {BitMaps} from &quot;@openzeppelin/contracts/utils/structs/BitMaps.sol&quot;;
import {MerkleProof} from &quot;@openzeppelin/contracts/utils/cryptography/MerkleProof.sol&quot;;

contract MerkleDrop {
    IERC20 public immutable tokenAddress;
    bytes32 public merkleRoot;
    BitMaps.BitMap internal airdropCheckList;

    constructor(address _tokenAddress, bytes32 _merkleRoot) {
        tokenAddress = IERC20(_tokenAddress);
        merkleRoot = _merkleRoot;
    }

    function claimAirDrop(bytes32[] calldata proof, uint256 index, uint256 amount) external {
        require(!BitMaps.get(airdropCheckList, index), &quot;Already claimed&quot;);

        bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender, index, amount))));
        require(MerkleProof.verify(proof, merkleRoot, leaf), &quot;Invalid proof&quot;);

        BitMaps.setTo(airdropCheckList, index, true);
        tokenAddress.transfer(msg.sender, amount);
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.24;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">BitMaps</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/utils/structs/BitMaps.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">MerkleProof</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">MerkleDrop</span> </span>{
    IERC20 <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> tokenAddress;
    <span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">public</span> merkleRoot;
    BitMaps.BitMap <span class="hljs-keyword">internal</span> airdropCheckList;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _tokenAddress, <span class="hljs-keyword">bytes32</span> _merkleRoot</span>) </span>{
        tokenAddress <span class="hljs-operator">=</span> IERC20(_tokenAddress);
        merkleRoot <span class="hljs-operator">=</span> _merkleRoot;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimAirDrop</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span>[] <span class="hljs-keyword">calldata</span> proof, <span class="hljs-keyword">uint256</span> index, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>BitMaps.get(airdropCheckList, index), <span class="hljs-string">"Already claimed"</span>);

        <span class="hljs-keyword">bytes32</span> leaf <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">bytes</span>.<span class="hljs-built_in">concat</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encode</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, index, amount))));
        <span class="hljs-built_in">require</span>(MerkleProof.verify(proof, merkleRoot, leaf), <span class="hljs-string">"Invalid proof"</span>);

        BitMaps.setTo(airdropCheckList, index, <span class="hljs-literal">true</span>);
        tokenAddress.<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }
}
</code></pre><p>Key points in this contract:</p><ul><li><p>We use a bitmap to efficiently track claimed airdrops we could have used mapping but we are just trying to save a bit of 1(true) and 0(false) so using mapping will be an over kill .</p></li><li><p>The <code>claimAirDrop</code> function verifies the Merkle proof before transferring tokens.</p></li><li><p>Double-hashing is used to prevent <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://readmedium.com/en/https:/medium.com/rareskills/the-second-preimage-attack-for-merkle-trees-in-solidity-e9d74fe7fdcd">preimage attacks</a>.</p></li></ul><h3 id="h-3-generating-proofs-for-claims" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. Generating Proofs for Claims</h3><p>To claim their airdrop, users need to provide a Merkle proof. Here&apos;s how we can generate these proofs:</p><pre data-type="codeBlock" text="const { StandardMerkleTree } = require(&quot;@openzeppelin/merkle-tree&quot;);
const fs = require(&quot;fs&quot;);

function generateProof(address) {
  const tree = StandardMerkleTree.load(JSON.parse(fs.readFileSync(&quot;tree.json&quot;, &quot;utf8&quot;)));

  for (const [i, v] of tree.entries()) {
    if (v[0].toLowerCase() === address.toLowerCase()) {
      return {
        value: v,
        proof: tree.getProof(i),
      };
    }
  }

  throw new Error(`Address ${address} not found in Merkle tree`);
}

/// the output of this will be out proof that we will pass into the claimairdrop 
/// function
"><code>const { StandardMerkleTree } <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"@openzeppelin/merkle-tree"</span>);
const fs <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateProof</span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>) </span>{
  const tree <span class="hljs-operator">=</span> StandardMerkleTree.load(JSON.parse(fs.readFileSync(<span class="hljs-string">"tree.json"</span>, <span class="hljs-string">"utf8"</span>)));

  <span class="hljs-keyword">for</span> (const [i, v] of tree.entries()) {
    <span class="hljs-keyword">if</span> (v[<span class="hljs-number">0</span>].toLowerCase() <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>.toLowerCase()) {
      <span class="hljs-keyword">return</span> {
        <span class="hljs-built_in">value</span>: v,
        proof: tree.getProof(i),
      };
    }
  }

  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(`Address ${<span class="hljs-keyword">address</span>} not found in Merkle tree`);
}

<span class="hljs-comment">/// the output of this will be out proof that we will pass into the claimairdrop </span>
<span class="hljs-comment">/// function</span>
</code></pre><p>This function loads the Merkle tree from our JSON file and generates a proof for a given address.</p><h3 id="h-full-codebase" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Full Codebase</h3><p>If you want the full codebase, check out my <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Iam0TI/Merkle-Airdrop">GitHub repository</a> and wrote some hardhat tests too.</p><h2 id="h-gas-efficiency-and-scalability" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Gas Efficiency and Scalability</h2><p>The beauty of using Merkle trees for airdrops lies in their gas efficiency and scalability:</p><ol><li><p><strong>Constant Gas Cost</strong>: The gas cost for claiming an airdrop remains constant regardless of the number of total recipients.</p></li><li><p><strong>Minimal On-Chain Storage</strong>: Only the Merkle root is stored on-chain, not the entire list of recipients.</p></li><li><p><strong>Scalable to Millions</strong>: The system can handle millions of recipients without significant increases in complexity or cost.</p></li></ol><h2 id="h-security-considerations" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Security Considerations</h2><p>While Merkle trees provide an efficient solution, there are security aspects to consider:</p><ol><li><p><strong>Proof Generation</strong>: Ensure that proof generation is done securely off-chain.</p></li><li><p><strong>Double-Claiming Prevention</strong>: The bitmap in the contract prevents double-claiming.</p></li><li><p><strong>Root Updates</strong>: If the airdrop list needs updating, a new Merkle root can be set by the contract owner.</p></li></ol><h3 id="h-conclusion-security-without-sacrificewhy-merkle-trees-are-pure-genius" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Conclusion: Security Without Sacrifice—Why Merkle Trees Are Pure Genius</h3><p>Merkle Trees work like magic—but it’s all math! Here’s the quick rundown:</p><p>First, <strong>hash functions</strong> (like SHA-256) are super secure. They take any input, hash it, and even the tiniest change in the input completely alters the hash. This makes tampering with data nearly impossible.</p><p>Second, <strong>Merkle Trees are incredibly efficient</strong>. Even with millions of entries, verifying a single airdrop claim only takes a few steps. All you need is your claim and a few sibling hashes. The smart contract then verifies everything without storing huge amounts of data on-chain, keeping costs low while maintaining security.</p><p>The reason this system works so well is that it leverages the <strong>collision resistance</strong> of hash functions and the <strong>logarithmic structure</strong> of Merkle Trees. The Merkle Proof lets the contract efficiently check whether your data is part of a larger set, all while keeping on-chain operations minimal.</p><p>In short, Merkle Trees make airdrop verification <strong>fast, secure, and scalable</strong>. Pretty genius, right?</p><h3 id="h-thanks-for-sticking-with-me" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Thanks for Sticking With Me!</h3><p>If you’ve made it this far, pat yourself on the back! You’re now well-versed in the magical world of Merkle Trees, and you’ve seen firsthand how they can make airdrop distribution (and other use cases) both <strong>scalable</strong> and <strong>secure</strong>. It’s not every day that you dive into the inner workings of cryptographic proofs and come out on the other side with a smile!</p><p>So, whether you&apos;re a developer looking to implement this system, or someone just curious about how blockchain sorcery works under the hood, I hope you enjoyed the ride! Thanks for reading to the end—and remember, you now hold the power of <strong>Merkle Magic</strong> in your hands!</p><p>Go forth and prove your membership with confidence!</p><h3 id="h-refrecences" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Refrecences</h3><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hackernoon.com/merkle-trees-181cb4bc30b4">https://hackernoon.com/merkle-trees-181cb4bc30b4</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=Iv0cPT-7AR8&amp;t=281s">Merkle Trees for Airdrops on EVM: Logic, Use Cases, and Solidity Implementation</a> (I strongly recommend)</p></li></ul>]]></content:encoded>
            <author>iamoti@newsletter.paragraph.com (IAMOTI)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9f7907866160fdf89e35b192fdb1b150b310030c17614c290e12a8ae3e7c49c8.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[ALL about sending Ether - Transfer, Call , Send]]></title>
            <link>https://paragraph.com/@iamoti/all-about-sending-ether-transfer-call-send</link>
            <guid>HJAHntKYCOrc6thZ4DJf</guid>
            <pubDate>Fri, 30 Aug 2024 22:45:02 GMT</pubDate>
            <description><![CDATA[Sending Ether in Solidity: A Comprehensive Technical GuideIntroductionSending Ether is a fundamental operation in Ethereum smart contracts. Over time, the recommended methods for transferring Ether have evolved due to security considerations and changes in the Ethereum protocol. This article will explore the three main methods of sending Ether: transfer(), send(), and call(), discussing their technical aspects, pros, cons, and current best practices.The Three Methods of Sending Ether1. transf...]]></description>
            <content:encoded><![CDATA[<h1 id="h-sending-ether-in-solidity-a-comprehensive-technical-guide" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Sending Ether in Solidity: A Comprehensive Technical Guide</h1><h2 id="h-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h2><p>Sending Ether is a fundamental operation in Ethereum smart contracts. Over time, the recommended methods for transferring Ether have evolved due to security considerations and changes in the Ethereum protocol. This article will explore the three main methods of sending Ether: <code>transfer()</code>, <code>send()</code>, and <code>call()</code>, discussing their technical aspects, pros, cons, and current best practices.</p><h2 id="h-the-three-methods-of-sending-ether" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Three Methods of Sending Ether</h2><h3 id="h-1-transfer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. transfer()</h3><p>The <code>transfer()</code> function was introduced in later versions of Solidity as a safer alternative for sending Ether.</p><p><strong>Syntax:</strong></p><pre data-type="codeBlock" text="receivingAddress.transfer(amount);
"><code>receivingAddress.<span class="hljs-built_in">transfer</span>(amount);
</code></pre><p><strong>Key Features:</strong></p><ul><li><p>Has a fixed gas stipend of 2300 gas</p></li><li><p>Automatically reverts the transaction if the transfer fails</p></li><li><p>Throws an exception on failure, allowing the calling contract to handle the error</p></li></ul><p><strong>Initial Appeal:</strong></p><ol><li><p>Automatic reversion: If the transfer failed, the transaction would automatically revert.</p></li><li><p>Fixed gas stipend: It forwarded a fixed amount of 2300 gas to the receiving contract.</p></li></ol><p><strong>Limitations and Issues:</strong></p><ul><li><p>The fixed gas stipend can cause problems if gas costs change</p></li><li><p>May fail if the receiving contract&apos;s fallback function requires more than 2300 gas</p></li><li><p>Relies on fixed gas costs, making it vulnerable to network upgrades that change opcode gas costs</p></li></ul><p><strong>Current Status:</strong> No longer recommended due to its reliance on fixed gas costs.</p><h3 id="h-2-send" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. send()</h3><p>The <code>send()</code> function is similar to <code>transfer()</code> but with slightly different behavior.</p><p><strong>Syntax:</strong></p><pre data-type="codeBlock" text="bool success = receivingAddress.send(amount);
"><code><span class="hljs-keyword">bool</span> success <span class="hljs-operator">=</span> receivingAddress.<span class="hljs-built_in">send</span>(amount);
</code></pre><p><strong>Key Features:</strong></p><ul><li><p>Also has a fixed gas stipend of 2300 gas</p></li><li><p>Returns a boolean indicating success or failure</p></li><li><p>Does not automatically revert the transaction on failure</p></li></ul><p><strong>Limitations:</strong></p><ul><li><p>Shares the same gas stipend limitations as <code>transfer()</code></p></li><li><p>Requires manual checking of the return value and error handling</p></li></ul><p><strong>Current Status:</strong> Not recommended due to the same issues as <code>transfer()</code>.</p><h3 id="h-3-call" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. call()</h3><p>The <code>call()</code> function is currently the recommended method for sending Ether.</p><p><strong>Syntax:</strong></p><pre data-type="codeBlock" text="(bool success, bytes memory data) = receivingAddress.call{value: amount}(&quot;&quot;);
"><code>(<span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data) <span class="hljs-operator">=</span> receivingAddress.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: amount}(<span class="hljs-string">""</span>);
</code></pre><p><strong>Key Features:</strong></p><ul><li><p>Allows for customizable gas limits</p></li><li><p>Returns a boolean for success/failure and any return data</p></li><li><p>More flexible, allowing for function calls along with Ether transfers</p></li></ul><p><strong>Advantages:</strong></p><ul><li><p>Not limited by fixed gas stipends</p></li><li><p>Can adapt to changes in gas costs</p></li><li><p>Provides more control over the transaction</p></li><li><p>Allows transfer of data with ether</p></li></ul><p><strong>Considerations:</strong></p><ul><li><p>Requires careful implementation to prevent re-entrancy attacks</p></li><li><p>Needs manual checking of the return value and error handling</p></li></ul><h2 id="h-the-impact-of-changing-opcode-gas-costs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Impact of Changing Opcode Gas Costs</h2><p>The fundamental issue with <code>transfer()</code> and <code>send()</code> lies in their reliance on a fixed gas stipend, which becomes problematic when gas costs for opcodes change. The Ethereum network periodically undergoes upgrades that can alter the gas costs of various operations, including storage operations (SSTORE and SLOAD).</p><h3 id="h-the-constantinople-upgrade-a-case-study" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Constantinople Upgrade: A Case Study</h3><p>The Constantinople upgrade in 2019 provides a clear example of how network changes can affect existing smart contracts. This upgrade aimed to optimize the network by reducing gas costs for certain SSTORE operations. While this change was beneficial in many ways, it had an unexpected consequence for contracts relying on <code>transfer()</code> and <code>send()</code>.</p><p>Prior to the upgrade, the 2300 gas stipend was insufficient to perform storage operations, which was seen as a security feature preventing reentrancy attacks. However, the reduced gas costs meant that this stipend could now potentially allow for storage modifications, opening up new attack vectors.</p><h2 id="h-best-practices-for-sending-ether" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Best Practices for Sending Ether</h2><p>Given the lessons learned from the <code>transfer()</code> and <code>send()</code> deprecation, here are some best practices for sending Ether:</p><ol><li><p><strong>Use</strong> <code>call()</code> instead of <code>transfer()</code> or <code>send()</code>: This is the current recommendation from the Ethereum community.</p></li><li><p><strong>Implement reentrancy guards:</strong> When using <code>call()</code>, always protect against reentrancy attacks.</p></li><li><p><strong>Check return values:</strong> Always check the success boolean returned by <code>call()</code> and handle failures appropriately.</p><ol><li><p>**Follow the checks-effects-interactions patternn                     **</p></li></ol></li></ol><h2 id="h-example-implementation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Example Implementation</h2><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SafeEtherSender {
    // Reentrancy guard
    bool private locked = false;

    modifier noReentrant() {
        require(!locked, &quot;No reentrancy&quot;);
        locked = true;
        _;
        locked = false;
    }

    function sendEther(address payable _to, uint256 _amount) public payable noReentrant {
        // Perform any necessary checks
        require(_amount &lt;= address(this).balance, &quot;Insufficient balance&quot;);

        // Use call to send Ether
        (bool success, ) = _to.call{value: _amount}(&quot;&quot;);
        require(success, &quot;Failed to send Ether&quot;);

        // Emit an event or perform any post-send operations
        emit EtherSent(_to, _amount);
    }

    event EtherSent(address indexed to, uint256 amount);
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SafeEtherSender</span> </span>{
    <span class="hljs-comment">// Reentrancy guard</span>
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">private</span> locked <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">noReentrant</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>locked, <span class="hljs-string">"No reentrancy"</span>);
        locked <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">_</span>;
        locked <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendEther</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> _to, <span class="hljs-keyword">uint256</span> _amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">noReentrant</span> </span>{
        <span class="hljs-comment">// Perform any necessary checks</span>
        <span class="hljs-built_in">require</span>(_amount <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>, <span class="hljs-string">"Insufficient balance"</span>);

        <span class="hljs-comment">// Use call to send Ether</span>
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> _to.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: _amount}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Failed to send Ether"</span>);

        <span class="hljs-comment">// Emit an event or perform any post-send operations</span>
        <span class="hljs-keyword">emit</span> EtherSent(_to, _amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">EtherSent</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> to, <span class="hljs-keyword">uint256</span> amount</span>)</span>;
}
</code></pre><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h2><p>The evolution of Ether sending methods in Solidity serves as an important reminder of the dynamic nature of blockchain networks. While <code>transfer()</code> and <code>send()</code> were once considered safe methods for sending Ether, changes in the Ethereum protocol have made them less reliable.</p><p>The current best practice is to use <code>call()</code> with proper safeguards against reentrancy and other potential vulnerabilities. This method offers more flexibility and resilience to network changes, but it requires developers to implement additional security measures.</p><p>As the Ethereum ecosystem continues to evolve, it&apos;s crucial for developers to create flexible, adaptable smart contracts that can withstand changes in the underlying protocol. By understanding the reasons behind the shift away from <code>transfer()</code> and <code>send()</code>, and adopting best practices, developers can create more robust and future-proof smart contracts.</p><p>Always stay updated with the latest Ethereum security recommendations and be prepared to adapt your code as the ecosystem evolves. Regular audits and updates to smart contracts are essential to ensure they remain secure and functional in the face of network changes.</p><h2 id="h-reference" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/sending-ether/">https://solidity-by-example.org/sending-ether/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blockchain-academy.hs-mittweida.de/courses/solidity-coding-beginners-to-intermediate/lessons/solidity-2-sending-ether-receiving-ether-emitting-events/topic/sending-ether-send-vs-transfer-vs-call/">https://blockchain-academy.hs-mittweida.de/courses/solidity-coding-beginners-to-intermediate/lessons/solidity-2-sending-ether-receiving-ether-emitting-events/topic/sending-ether-send-vs-transfer-vs-call/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.immunebytes.com/blog/transfer-in-solidity-why-you-should-stop-using-it/">https://www.immunebytes.com/blog/transfer-in-solidity-why-you-should-stop-using-it/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/solidity/issues/7455">https://github.com/ethereum/solidity/issues/7455</a></p><ol start="2"><li><br></li></ol>]]></content:encoded>
            <author>iamoti@newsletter.paragraph.com (IAMOTI)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/4617e6f8392bab0b7ed10e07a5f6ef230caa640fe46e8ce525efb402b62050cc.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[ALL ABOUT ERCs  - ERC20 TOKEN STANDARD]]></title>
            <link>https://paragraph.com/@iamoti/all-about-ercs-erc20-token-standard</link>
            <guid>3YmU2520H1p68yWvgNqt</guid>
            <pubDate>Tue, 27 Aug 2024 11:45:07 GMT</pubDate>
            <description><![CDATA[A deep dive into the specification and Implementation of ERC20 token standard .Welcome back... ohh wait this is the first blog .In today&apos;s article, we cover in more detail one of the most important ERC in the smart contract development We will see how the ERC20 the contract works, how to write and deploy our every own ERC20 Token. We will also use some contracts from OpenZeppelin to learn how the ERC20 token implementation work in practice while learning the Solidity code behind these po...]]></description>
            <content:encoded><![CDATA[<h3 id="h-a-deep-dive-into-the-specification-and-implementation-of-erc20-token-standard" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">A deep dive into the specification and Implementation of ERC20 token standard .</h3><p>Welcome back... ohh wait this is the first blog .In today&apos;s article, we cover in more detail one of the most important ERC in the smart contract development</p><p>We will see how the ERC20 the contract works, how to write and deploy our every own ERC20 Token. We will also use some contracts from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/">OpenZeppelin</a> to learn how the ERC20 token implementation work in practice while learning the Solidity code behind these popular contracts along the way.</p><h3 id="h-table-of-content" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Table Of Content .</h3><ul><li><p>Introduction</p></li><li><p>Anatomy of an ERC-20 Token</p></li><li><p>Deep dive into Openzepplin Implementation</p></li><li><p>Conclusion</p></li></ul><h2 id="h-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h2><p>Have ever wondered why every website you have evere visited uses <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/HTTP">HTTP</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/HTTPS">HTTPS</a> ? This is because of something called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Request_for_Comments">RFCs</a> , or &quot;Requests for Comments,&quot; which are the standards that define how the internet operates. RFCs provide the foundational rules that enable different systems to communicate seamlessly, ensuring a consistent experience across the web. Similarly, in the world of blockchain, particularly within the Ethereum ecosystem, we have Ethereum Improvement Proposal (EIPs) and <strong>Ethereum Request for Comments (ERCs)</strong>.</p><p><strong>EIPs</strong> are proposals that outline new features or standards for Ethereum, guiding its ongoing development and improvement. Among these EIPs, certain proposals evolve into <strong>ERCs</strong> when they define specific technical standards for smart contracts and tokens, much like how certain RFCs become the backbone of internet protocols.</p><p>One of the most prominent and widely adopted ERCs is <strong>ERC-20</strong>. This standard governs the creation and behavior of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cointelegraph.com/learn/fungible-vs-nonfungible-tokens-what-is-the-difference">fungible tokens on Ethereum</a>, establishing a set of rules that all ERC-20 tokens must follow. Just as HTTP/HTTPS ensures that all web browsers and servers can communicate efficiently, ERC-20 ensures that all tokens within its framework are interoperable across various platforms, wallets, and decentralized applications (DApps). Whether it&apos;s trading on decentralized exchanges or integrating with DeFi platforms, ERC-20 provides the necessary standardization that enables the smooth functioning of the Ethereum token ecosystem. In this article, we will delve into the ERC-20 specification, exploring its key functions, events, and how it can be implemented in smart contracts.</p><h3 id="h-but-wait" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">But wait ...</h3><p>Before we start we need to get something right , the difference between EIP20 and ERC20. EIP-20 and ERC-20 refer to the same standard for fungible tokens on Ethereum &quot;EIP-20&quot; is the official Ethereum Improvement Proposal defining the standard, while &quot;ERC-20&quot; (Ethereum Request for Comments 20) is the common term used to describe tokens that follow this standard. Both terms are often used interchangeably.</p><h2 id="h-anatomy-of-an-erc-20-token" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Anatomy of an ERC-20 Token</h2><p>An ERC-20 token according to the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-20">EIP-20</a> consists of a smart contract that implements the standardized interface, which comprises a set of six mandatory functions:</p><ul><li><p><strong>totalSupply():</strong> Returns the total supply of the token.</p></li><li><p><strong>balanceOf(address):</strong> Provides the balance of tokens held by a specific address.</p></li><li><p><strong>transfer(address, uint256):</strong> Transfers a specified amount of tokens from the sender&apos;s address to the specified recipient&apos;s address.</p></li><li><p><strong>transferFrom(address, address, uint256):</strong> Enables a third party to transfer tokens on behalf of the token owner, given that the owner has approved the transaction.</p></li><li><p><strong>approve(address, uint256):</strong> Allows the token owner to grant permission to a third party to spend a specified amount of tokens on their behalf.</p></li><li><p><strong>allowance(address, address):</strong> Returns the amount of tokens the token owner has allowed a third party to spend on their behalf.</p></li></ul><p>Additionally, ERC-20 tokens can include optional functions that provide descriptive information about the token:</p><ul><li><p><strong>name():</strong> Returns the name of the token, for example, &quot;WEB3BRIDGE&quot;</p></li><li><p><strong>symbol():</strong> Provides the token&apos;s symbol, like &quot;WEB3BD&quot;</p></li><li><p><strong>decimals():</strong> Indicates the number of decimal places the token can be divided into, typically 18 for most tokens.</p></li></ul><h3 id="h-deep-dive-into-openzepplin-implementation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Deep dive into Openzepplin Implementation</h3><p>Enough of the boring stuff let&apos;s get into the code ): . This of the article assumes you are familiar with Solidity . We will we explaining every block of code in the Openzepplin ERC.sol contract with you can find <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol">here</a> and how it relates to the original EIP-20 specification.</p><p>In the code there are three types of functions (View, Internal and Public). But before we go over the functions let&apos;s check out the state variable and imports</p><h5 id="h-the-imports" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">The imports</h5><pre data-type="codeBlock" text="pragma solidity ^0.8.20;

import {IERC20} from &quot;./IERC20.sol&quot;;
import {IERC20Metadata} from &quot;./extensions/IERC20Metadata.sol&quot;;
import {Context} from &quot;../../utils/Context.sol&quot;;
import {IERC20Errors} from &quot;../../interfaces/draft-IERC6093.sol&quot;;
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20Metadata</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./extensions/IERC20Metadata.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Context</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../../utils/Context.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20Errors</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../../interfaces/draft-IERC6093.sol"</span>;
</code></pre><ul><li><p><em>import {IERC20} from &quot;./IERC20.sol&quot;;</em> : Imports the ERC20 interface defining the core functions for token transfers, allowances, and balance queries, which all ERC20 tokens must implement.</p></li><li><p><em>import {IERC20Metadata} from &quot;./extensions/IERC20Metadata.sol&quot;;</em> : Imports the ERC20Metadata interface that extends the basic ERC20 interface by adding functions for querying token name, symbol, and decimals.</p></li><li><p><em>import {Context} from &quot;../../utils/Context.sol&quot;;</em> : Imports the Context contract, which provides information about the current execution context, such as the sender of the transaction, useful for implementing access control.</p></li><li><p><em>import {IERC20Errors} from &quot;../../interfaces/draft-IERC6093.sol&quot;;</em> : Imports the IERC20Errors interface, which defines common error codes for ERC20 operations, ensuring standardized error handling.</p></li></ul><p>The state variable</p><pre data-type="codeBlock" text="// to track individual account and the ammount of token own by them
mapping(address account =&gt; uint256) private _balances;

// this is a 2d mapping i will explain soon
mapping(address account =&gt; mapping(address spender =&gt; uint256))
  private _allowances;

// to store the total supply
    uint256 private _totalSupply;

// to store the token name
    string private _name;
// to store the token symbol
    string private _symbol;
"><code><span class="hljs-comment">// to track individual account and the ammount of token own by them</span>
<span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> account <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">private</span> _balances;

<span class="hljs-comment">// this is a 2d mapping i will explain soon</span>
<span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> account <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> spender <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>))
  <span class="hljs-keyword">private</span> _allowances;

<span class="hljs-comment">// to store the total supply</span>
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> _totalSupply;

<span class="hljs-comment">// to store the token name</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> _name;
<span class="hljs-comment">// to store the token symbol</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> _symbol;
</code></pre><h2 id="h-constructor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Constructor</h2><p>The <code>constructor</code> of a smart contract runs once, during deployment, and allows the deployer to define custom data for the initial contract state. For <code>ERC20.sol</code>, the constructor takes 2 parameters to determine the name and the symbol of the token .</p><pre data-type="codeBlock" text="// the constructor intailize the state variable _name and _symbol
constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }
"><code><span class="hljs-comment">// the constructor intailize the state variable _name and _symbol</span>
<span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> name_, <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> symbol_</span>) </span>{
        _name <span class="hljs-operator">=</span> name_;
        _symbol <span class="hljs-operator">=</span> symbol_;
    }
</code></pre><h3 id="h-getter-functions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Getter Functions</h3><p>Getter functions are public view functions in the contract that allow users to read the state (state variables )of a smart contract. For <code>ERC20.sol</code>, we can see the following getter functions.</p><pre data-type="codeBlock" text="// this function returns the name of erc20 token
function name() public view virtual returns (string memory) {
        return _name;
    }
// this function returns the number of decimal places used by the ERC20 token.
// Decimal places determine the smallest unit of the token that can be represented and transacted.
// For example, if a token has 18 decimals, 
//it can be divided into 10^18 (1,000,000,000,000,000,000) smaller units.
// This is important for precision in financial calculations and 
//token transfers, allowing for very fine-grained transactions.
// The standard setting for most ERC20 tokens is 18 decimals,
//which aligns with Ethereum&apos;s own precision for Ether (ETH) to  
//wei since 1 ETHER is 10^18 wei.
  function decimals() public view virtual returns (uint8) {
        return 18;
    }
// this function returns the symbol of the ERC20 token.
 function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

// this function returns the total supply of the ERC20 token.
// the total supply is the total amount of tokens that exist in circulation.
 function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

// remember the state variable the  mapping of a the balances to owner.
// this function returns the balance of tokens held by a specific account.
// it provides the amount of tokens that the account address has in its balance.

 function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }
// it remain the the allowances view function more about that later
"><code><span class="hljs-comment">// this function returns the name of erc20 token</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">name</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> _name;
    }
<span class="hljs-comment">// this function returns the number of decimal places used by the ERC20 token.</span>
<span class="hljs-comment">// Decimal places determine the smallest unit of the token that can be represented and transacted.</span>
<span class="hljs-comment">// For example, if a token has 18 decimals, </span>
<span class="hljs-comment">//it can be divided into 10^18 (1,000,000,000,000,000,000) smaller units.</span>
<span class="hljs-comment">// This is important for precision in financial calculations and </span>
<span class="hljs-comment">//token transfers, allowing for very fine-grained transactions.</span>
<span class="hljs-comment">// The standard setting for most ERC20 tokens is 18 decimals,</span>
<span class="hljs-comment">//which aligns with Ethereum's own precision for Ether (ETH) to  </span>
<span class="hljs-comment">//wei since 1 ETHER is 10^18 wei.</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decimals</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint8</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">18</span>;
    }
<span class="hljs-comment">// this function returns the symbol of the ERC20 token.</span>
 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">symbol</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> _symbol;
    }

<span class="hljs-comment">// this function returns the total supply of the ERC20 token.</span>
<span class="hljs-comment">// the total supply is the total amount of tokens that exist in circulation.</span>
 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalSupply</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> _totalSupply;
    }

<span class="hljs-comment">// remember the state variable the  mapping of a the balances to owner.</span>
<span class="hljs-comment">// this function returns the balance of tokens held by a specific account.</span>
<span class="hljs-comment">// it provides the amount of tokens that the account address has in its balance.</span>

 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> _balances[account];
    }
<span class="hljs-comment">// it remain the the allowances view function more about that later</span>
</code></pre><p>Before going further into the code we need to understand some concept such transfer,approval and allowance</p><h4 id="h-balances-and-transfers-in-erc-20" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Balances and Transfers in ERC-20</h4><p>The ERC-20 token contract plays a crucial role in managing user balances and facilitating token transfers. Think of it as a digital ledger that tracks ownership and transactions of tokens.</p><p>Token Balances</p><p>An ERC-20 contract must keep track of the balance of each user, which can be read by calling the <code>balanceOf(address)</code> view function. This function takes in an address and returns the amount of tokens owned by that address.</p><p>In many ERC-20 implementations, the entire initial supply of tokens is typically assigned to the contract creator when the contract is deployed. And the initial supply of token can be set by a process called mint</p><pre data-type="codeBlock" text=" function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
   // will explain this function soon
        _update(address(0), account, value);
    }
"><code> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
        <span class="hljs-keyword">if</span> (account <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">revert</span> ERC20InvalidReceiver(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
        }
   <span class="hljs-comment">// will explain this function soon</span>
        _update(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), account, value);
    }
</code></pre><h4 id="h-direct-token-transfers" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Direct Token Transfers</h4><p>ERC-20 tokens can be transferred between users in two primary ways. The first method involves the sender directly instructing the ERC-20 contract to transfer tokens to a recipient by calling the <code>transfer(address _to, uint256 _amount)</code> function.</p><ul><li><p><strong>Function:</strong> <code>transfer(address _to, uint256 _amount) → bool</code></p></li><li><p><strong>Description:</strong> Transfers <code>_amount</code> of tokens from the sender (<code>msg.sender</code>) to the recipient (<code>_to</code>). Returns <code>true</code> if the transfer is successful, otherwise the transaction reverts.</p></li></ul><p>The <code>transfer</code> function deducts the specified amount from the sender&apos;s balance and credits it to the recipient&apos;s balance. If the sender does not have enough tokens, the function will revert the transaction. In most ERC-20 implementations, if the transfer is valid, it will always return <code>true</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ff571b7aaff7b00098cc09c72bd7e529832f275b0a50fa13f8dff94706d1b02f.webp" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><pre data-type="codeBlock" text="function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }
// this is a helper function to help user check if they are not
//sending to a zero address like my great mentor with it help perform sanity check
 function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
          
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
   
        _update(from, to, value);
    }

  // This is way the main logic is implemented
 // the function to update balances and total supply during token transfers or minting/burning.
 // If `from` is the zero address, tokens are being minted, so the total supply is increased by `value`.
 // - If `to` is the zero address, tokens are being burned, so the total supply is decreased by `value`.
 // Otherwise, tokens are being transferred: the balance of `from` is decreased by `value` 
//(reverting if insufficient), and the balance of `to` is increased by `value`.
 // The function ensures that overflows are not possible and that total supply remains consistent.
 

 function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance &lt; value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value &lt;= fromBalance &lt;= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value &lt;= totalSupply or value &lt;= fromBalance &lt;= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">address</span> owner <span class="hljs-operator">=</span> _msgSender();
        _transfer(owner, to, value);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
<span class="hljs-comment">// this is a helper function to help user check if they are not</span>
<span class="hljs-comment">//sending to a zero address like my great mentor with it help perform sanity check</span>
 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
          
            <span class="hljs-keyword">revert</span> ERC20InvalidSender(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
        }
        <span class="hljs-keyword">if</span> (to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">revert</span> ERC20InvalidReceiver(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
        }
   
        _update(<span class="hljs-keyword">from</span>, to, value);
    }

  <span class="hljs-comment">// This is way the main logic is implemented</span>
 <span class="hljs-comment">// the function to update balances and total supply during token transfers or minting/burning.</span>
 <span class="hljs-comment">// If `from` is the zero address, tokens are being minted, so the total supply is increased by `value`.</span>
 <span class="hljs-comment">// - If `to` is the zero address, tokens are being burned, so the total supply is decreased by `value`.</span>
 <span class="hljs-comment">// Otherwise, tokens are being transferred: the balance of `from` is decreased by `value` </span>
<span class="hljs-comment">//(reverting if insufficient), and the balance of `to` is increased by `value`.</span>
 <span class="hljs-comment">// The function ensures that overflows are not possible and that total supply remains consistent.</span>
 

 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_update</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-comment">// Overflow check required: The rest of the code assumes that totalSupply never overflows</span>
            _totalSupply <span class="hljs-operator">+</span><span class="hljs-operator">=</span> value;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">uint256</span> fromBalance <span class="hljs-operator">=</span> _balances[<span class="hljs-keyword">from</span>];
            <span class="hljs-keyword">if</span> (fromBalance <span class="hljs-operator">&#x3C;</span> value) {
                <span class="hljs-keyword">revert</span> ERC20InsufficientBalance(<span class="hljs-keyword">from</span>, fromBalance, value);
            }
            <span class="hljs-keyword">unchecked</span> {
                <span class="hljs-comment">// Overflow not possible: value &#x3C;= fromBalance &#x3C;= totalSupply.</span>
                _balances[<span class="hljs-keyword">from</span>] <span class="hljs-operator">=</span> fromBalance <span class="hljs-operator">-</span> value;
            }
        }

        <span class="hljs-keyword">if</span> (to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">unchecked</span> {
                <span class="hljs-comment">// Overflow not possible: value &#x3C;= totalSupply or value &#x3C;= fromBalance &#x3C;= totalSupply.</span>
                _totalSupply <span class="hljs-operator">-</span><span class="hljs-operator">=</span> value;
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">unchecked</span> {
                <span class="hljs-comment">// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.</span>
                _balances[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> value;
            }
        }
</code></pre><h4 id="h-approved-token-transfers" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Approved Token Transfers</h4><p>The second method for transferring tokens involves a more indirect process where:</p><ol><li><p>The token owner first approves another address (referred to as the &quot;spender&quot;) to spend a certain amount of tokens on their behalf.</p></li><li><p>The approved spender then initiates a transfer from the owner&apos;s address to a recipient.</p></li></ol><p>This method is particularly useful in scenarios where smart contracts, such as decentralized exchanges, need to manage tokens on behalf of users. The ERC-20 standard includes the <code>approve</code> and <code>transferFrom</code> functions to facilitate this form of transfer. The amount that a spender is authorized to transfer can be checked using the <code>allowance</code> view function.</p><ul><li><p><strong>Function:</strong> <code>allowance(address _owner, address _spender) → uint256</code></p></li><li><p><strong>Description:</strong> Returns the remaining number of tokens that <code>_spender</code> is allowed to transfer on behalf of <code>_owner</code>.</p></li><li><p><strong>Function:</strong> <code>approve(address _spender, uint256 _amount) → bool</code></p></li><li><p><strong>Description:</strong> Approves <code>_spender</code> to transfer up to <code>_amount</code> of tokens from the sender&apos;s (<code>msg.sender</code>) account. Returns <code>true</code> if the approval is successful.</p></li><li><p><strong>Function:</strong> <code>transferFrom(address _from, address _to, uint256 _amount) → bool</code></p></li><li><p><strong>Description:</strong> Transfers <code>_amount</code> of tokens from <code>_from</code> to <code>_to</code>, using the allowance mechanism. The caller (<code>msg.sender</code>) must have prior approval from <code>_from</code>. Returns <code>true</code> if the transfer is successful, otherwise the transaction reverts.</p></li></ul><p>The <code>transferFrom</code> function will decrease the spender&apos;s allowance by the amount transferred. If there are insufficient funds or the allowance is too low, the transaction will revert. As with direct transfers, the function generally either returns <code>true</code> or reverts if it encounters an error.</p><pre data-type="codeBlock" text="
     /**
 * This function handles token transfers on behalf of a third party. 
 * When a user (the &quot;spender&quot;) wants to transfer tokens from someone else&apos;s account 
 * (the &quot;from&quot; address), this function is used. First, it ensures the spender is 
 * allowed to move the specified amount of tokens by checking their allowance. 
 * If everything checks out, the function proceeds to transfer the tokens 
 * from the &quot;from&quot; address to the &quot;to&quot; address. Finally, it returns `true` 
 * to signal that the transfer was successful.
 */
function transferFrom(
    address from,
    address to,
    uint256 value
) public virtual returns (bool) {
    address spender = _msgSender();  // Identify who is trying to spend the tokens.
    _spendAllowance(from, spender, value);  // Make sure the spender has permission to spend this amount.
    _transfer(from, to, value);  // Perform the actual transfer of tokens.
    return true;  // Confirm that the transfer was successful.
}

/**
 * Before a spender can transfer tokens on someone else’s behalf, we need to make sure 
 * they have the right to do so. This function checks the current allowance (the maximum 
 * amount the spender is allowed to transfer) and then reduces it by the amount being transferred. 
 * If the spender tries to transfer more than their allowance, the function will stop the transaction. 
 * If the allowance is valid, it gets adjusted downwards to reflect the new balance.
 */
function _spendAllowance(
    address owner,
    address spender,
    uint256 value
) internal virtual {
    uint256 currentAllowance = allowance(owner, spender);  // Check the current allowance.
    if (currentAllowance != type(uint256).max) {  // If allowance isn&apos;t unlimited, verify and adjust it.
        if (currentAllowance &lt; value) {  // Stop the transaction if the allowance is too low.
            revert ERC20InsufficientAllowance(
                spender,
                currentAllowance,
                value
            );
        }
        unchecked {
            _approve(owner, spender, currentAllowance - value, false);  // Reduce the allowance by the amount spent.
        }
    }
}

/**
 * The `_approve` function is the workhorse behind setting allowances. 
 * It updates the amount of tokens that a spender is allowed to use on behalf of the owner. 
 * If needed, it also triggers an event to notify the network of the new allowance, 
 * although in some cases (like internal adjustments) the event might not be necessary. 
 * This function ensures that everything stays in sync and that all transactions are transparent.
 */
function _approve(
    address owner,
    address spender,
    uint256 value,
    bool emitEvent
) internal virtual {
    _allowances[owner][spender] = value;  // Set the new allowance amount.

    if (emitEvent) {
        emit Approval(owner, spender, value);  // Emit an event to log this action, if necessary.
    }
}
"><code>
     <span class="hljs-comment">/**
 * This function handles token transfers on behalf of a third party. 
 * When a user (the "spender") wants to transfer tokens from someone else's account 
 * (the "from" address), this function is used. First, it ensures the spender is 
 * allowed to move the specified amount of tokens by checking their allowance. 
 * If everything checks out, the function proceeds to transfer the tokens 
 * from the "from" address to the "to" address. Finally, it returns `true` 
 * to signal that the transfer was successful.
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferFrom</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
    <span class="hljs-keyword">address</span> to,
    <span class="hljs-keyword">uint256</span> value
</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
    <span class="hljs-keyword">address</span> spender <span class="hljs-operator">=</span> _msgSender();  <span class="hljs-comment">// Identify who is trying to spend the tokens.</span>
    _spendAllowance(<span class="hljs-keyword">from</span>, spender, value);  <span class="hljs-comment">// Make sure the spender has permission to spend this amount.</span>
    _transfer(<span class="hljs-keyword">from</span>, to, value);  <span class="hljs-comment">// Perform the actual transfer of tokens.</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;  <span class="hljs-comment">// Confirm that the transfer was successful.</span>
}

<span class="hljs-comment">/**
 * Before a spender can transfer tokens on someone else’s behalf, we need to make sure 
 * they have the right to do so. This function checks the current allowance (the maximum 
 * amount the spender is allowed to transfer) and then reduces it by the amount being transferred. 
 * If the spender tries to transfer more than their allowance, the function will stop the transaction. 
 * If the allowance is valid, it gets adjusted downwards to reflect the new balance.
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_spendAllowance</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> owner,
    <span class="hljs-keyword">address</span> spender,
    <span class="hljs-keyword">uint256</span> value
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
    <span class="hljs-keyword">uint256</span> currentAllowance <span class="hljs-operator">=</span> allowance(owner, spender);  <span class="hljs-comment">// Check the current allowance.</span>
    <span class="hljs-keyword">if</span> (currentAllowance <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>) {  <span class="hljs-comment">// If allowance isn't unlimited, verify and adjust it.</span>
        <span class="hljs-keyword">if</span> (currentAllowance <span class="hljs-operator">&#x3C;</span> value) {  <span class="hljs-comment">// Stop the transaction if the allowance is too low.</span>
            <span class="hljs-keyword">revert</span> ERC20InsufficientAllowance(
                spender,
                currentAllowance,
                value
            );
        }
        <span class="hljs-keyword">unchecked</span> {
            _approve(owner, spender, currentAllowance <span class="hljs-operator">-</span> value, <span class="hljs-literal">false</span>);  <span class="hljs-comment">// Reduce the allowance by the amount spent.</span>
        }
    }
}

<span class="hljs-comment">/**
 * The `_approve` function is the workhorse behind setting allowances. 
 * It updates the amount of tokens that a spender is allowed to use on behalf of the owner. 
 * If needed, it also triggers an event to notify the network of the new allowance, 
 * although in some cases (like internal adjustments) the event might not be necessary. 
 * This function ensures that everything stays in sync and that all transactions are transparent.
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_approve</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> owner,
    <span class="hljs-keyword">address</span> spender,
    <span class="hljs-keyword">uint256</span> value,
    <span class="hljs-keyword">bool</span> emitEvent
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
    _allowances[owner][spender] <span class="hljs-operator">=</span> value;  <span class="hljs-comment">// Set the new allowance amount.</span>

    <span class="hljs-keyword">if</span> (emitEvent) {
        <span class="hljs-keyword">emit</span> Approval(owner, spender, value);  <span class="hljs-comment">// Emit an event to log this action, if necessary.</span>
    }
}
</code></pre><p>I think with that we are done with the deep dive hope you are not drowning .</p><p>Here’s a simple example of a smart contract for a erc20 token:</p><pre data-type="codeBlock" text="pragma solidity ^0.8.20;

import &quot;@openzeppelin/contracts/token/ERC20/ERC20.sol&quot;;

contract DragonToken is ERC20 {
    constructor(uint256 initialSupply) ERC20(&quot;WEB3BRIDGE&quot;, &quot;WEB3BD&quot;) {
        _mint(msg.sender, initialSupply);
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

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

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DragonToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> initialSupply</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"WEB3BRIDGE"</span>, <span class="hljs-string">"WEB3BD"</span></span>) </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
    }
}
</code></pre><h3 id="h-conclusion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h3><p>In this article, we&apos;ve taken a deep dive into the ERC-20 standard, one of the foundational elements of smart contract development on Ethereum. We&apos;ve explored how ERC-20 contracts work, learned the key functions and mechanics behind them, and even looked at how to create one. By utilizing contracts from OpenZeppelin, we&apos;ve not only seen how these tokens are implemented in practice but also gained insight into the Solidity code that powers these widely-used contracts. With this knowledge, you&apos;re now equipped to leverage the ERC-20 standard in your own projects, ensuring interoperability and efficiency in the ever-expanding world of decentralized finance.</p><p>see you next time ...... IAM0TI</p>]]></content:encoded>
            <author>iamoti@newsletter.paragraph.com (IAMOTI)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/d06bae29b791915dc3725505c660dd6a24c324da96761336e7361e5659be1f37.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[HELLO WORLD IAM0TI]]></title>
            <link>https://paragraph.com/@iamoti/hello-world-iam0ti</link>
            <guid>sBffj9Tej2640dowrguE</guid>
            <pubDate>Tue, 27 Aug 2024 03:16:29 GMT</pubDate>
            <description><![CDATA[IAMOTI]]></description>
            <content:encoded><![CDATA[<p>IAMOTI</p>]]></content:encoded>
            <author>iamoti@newsletter.paragraph.com (IAMOTI)</author>
        </item>
    </channel>
</rss>