<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuanyan Wu</title>
    <description>The latest articles on DEV Community by Yuanyan Wu (@rwu_security_researcher).</description>
    <link>https://dev.to/rwu_security_researcher</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3053172%2Fa51c787f-4d92-4afb-a34d-f2992956659a.png</url>
      <title>DEV Community: Yuanyan Wu</title>
      <link>https://dev.to/rwu_security_researcher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rwu_security_researcher"/>
    <language>en</language>
    <item>
      <title>How to Fully Transfer ERC-20 Tokens Without Leaving Dust Using MetaMask and JavaScript</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Sun, 11 May 2025 19:45:36 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/how-to-fully-transfer-erc-20-tokens-without-leaving-dust-using-metamask-and-javascript-4o4f</link>
      <guid>https://dev.to/rwu_security_researcher/how-to-fully-transfer-erc-20-tokens-without-leaving-dust-using-metamask-and-javascript-4o4f</guid>
      <description>&lt;p&gt;Learn how to fully transfer your ERC-20 token balance from one Ethereum wallet to another using MetaMask and raw JavaScript, leaving no residual dust. This tutorial walks you through the process using Chrome DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ Prerequisite: Fund the Wallet With ETH
&lt;/h2&gt;

&lt;p&gt;ERC-20 token transfers require ETH to pay gas fees.&lt;/p&gt;

&lt;h3&gt;
  
  
  💸 How Much ETH Do You Need?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Action&lt;/th&gt;
      &lt;th&gt;Gas Estimate&lt;/th&gt;
      &lt;th&gt;ETH at 25 gwei&lt;/th&gt;
      &lt;th&gt;ETH at 40 gwei&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;ERC-20 transfer&lt;/td&gt;
      &lt;td&gt;~50,000–60,000 gas&lt;/td&gt;
      &lt;td&gt;~0.00125 ETH&lt;/td&gt;
      &lt;td&gt;~0.002 ETH&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To be safe, fund the source wallet with ~0.01 ETH. If gas prices are high, consider waiting for a weekend or late-night window when network demand is lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Step-by-Step: Transfer Full ERC-20 Balance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Step 1: Open Chrome and Unlock MetaMask
&lt;/h3&gt;

&lt;p&gt;Log in to MetaMask using your source wallet (the one holding the ERC-20 balance and ETH).&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Step 2: Open DevTools → Console (F12 or Ctrl+Shift+I)
&lt;/h3&gt;

&lt;p&gt;In the Console tab, type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it's undefined, follow the fixes below.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧰 Fixing MetaMask Injection Issues
&lt;/h4&gt;

&lt;p&gt;If window.ethereum is not available:&lt;/p&gt;

&lt;p&gt;✅ Check MetaMask Extension&lt;br&gt;
Go to chrome://extensions/ and verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MetaMask is installed&lt;/li&gt;
&lt;li&gt;It’s enabled&lt;/li&gt;
&lt;li&gt;Not in an error or paused state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Step 2: Use a Real HTTPS Page&lt;br&gt;
MetaMask doesn't inject into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file:// pages&lt;/li&gt;
&lt;li&gt;Some localhost pages&lt;/li&gt;
&lt;li&gt;Blank tabs or popups&lt;/li&gt;
&lt;li&gt;Use a trusted site like:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://etherscan.io" rel="noopener noreferrer"&gt;https://etherscan.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://remix.ethereum.org" rel="noopener noreferrer"&gt;https://remix.ethereum.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Step 3: Ensure MetaMask Permissions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the MetaMask icon&lt;/li&gt;
&lt;li&gt;If it says "Connect to site", click Connect&lt;/li&gt;
&lt;li&gt;Refresh the page&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✅ Step 3: Paste This Script in DevTools
&lt;/h3&gt;

&lt;p&gt;Once window.ethereum is available, paste the following script into the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xERC20ContractAddress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Replace with actual ERC-20 contract&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xTargetAddress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// Destination address&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sourceWallet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_requestAccounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Fetch token balance&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paddedAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sourceWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balanceHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x70a08231&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;paddedAddr&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balanceHex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Raw balance:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to read token balance:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Build transfer() data&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toPadded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valuePadded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xa9059cbb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;toPadded&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;valuePadded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Send transaction&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_sendTransaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sourceWallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;txData&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;✅ ERC-20 full transfer sent. TX Hash:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔍 Deep Dive: Understanding &lt;code&gt;eth_call&lt;/code&gt;, Function Selectors, and ABI Encoding
&lt;/h2&gt;

&lt;p&gt;After you paste and run the script, it may seem magical — but here's how it works under the hood.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 What is &lt;code&gt;eth_call&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;eth_call is an Ethereum JSON-RPC method that simulates a contract call locally without broadcasting a real transaction. It lets us read data from smart contracts (like balances or allowances) without paying gas.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧾 Understanding &lt;code&gt;data: 0x70a08231&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Every function in a smart contract is identified by a 4-byte function selector, which is the first 4 bytes of the keccak256 hash of the function signature.&lt;/p&gt;

&lt;p&gt;Example for balanceOf(address):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function Signature: "balanceOf(address)"&lt;/li&gt;
&lt;li&gt;keccak256:         0x70a082310000000000...&lt;/li&gt;
&lt;li&gt;Selector:           0x70a08231&lt;/li&gt;
&lt;li&gt;So calling balanceOf(address) with ABI-encoded arguments begins with 0x70a08231.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📚 Common ERC-20 Function Selectors
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Function&lt;/th&gt;
      &lt;th&gt;Signature&lt;/th&gt;
      &lt;th&gt;Selector&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Get token balance&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;balanceOf(address)&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;0x70a08231&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Transfer tokens&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;transfer(address,uint256)&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;0xa9059cbb&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can generate these with tools like: &lt;a href="https://pi7.org/hash/keccak-256" rel="noopener noreferrer"&gt;https://pi7.org/hash/keccak-256&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just paste in the raw signature string, like "balanceOf(address)"&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 ABI Argument Encoding
&lt;/h3&gt;

&lt;p&gt;Smart contract arguments must be padded to 32 bytes (64 hex characters). For example:&lt;/p&gt;

&lt;p&gt;If calling balanceOf("0x1234...5678"), the full data field is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x70a08231
+ 0000000000000000000000001234567890abcdef1234567890abcdef12345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The first part 0x70a08231 is the function selector&lt;/li&gt;
&lt;li&gt;The second part is the address, left-padded with zeros to 32 bytes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get the ERC-20 token balance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paddedAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x70a08231&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;paddedAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To send the full balance via transfer():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toPadded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amountPadded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xa9059cbb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;toPadded&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;amountPadded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding this encoding lets you interact with any smart contract method manually — without relying on third-party libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Confirm and Sign in MetaMask
&lt;/h2&gt;

&lt;p&gt;MetaMask will prompt you to approve the token transfer.&lt;/p&gt;

&lt;p&gt;Once confirmed and mined, your ERC-20 balance will be fully transferred, with no dust left behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Why Not Just Use Wallet UIs?
&lt;/h2&gt;

&lt;p&gt;Most wallets (like MetaMask, Rabby, etc.) limit the number of decimal places shown or used during transfers. As a result, they may leave small residual amounts (“dust”) in the wallet to avoid failed transactions due to precision or gas misestimation.&lt;/p&gt;

&lt;p&gt;By using raw eth_call and manual ABI encoding, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move the exact token amount&lt;/li&gt;
&lt;li&gt;Pay only the required gas&lt;/li&gt;
&lt;li&gt;Leave nothing behind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔖 Bookmark This for Future Sweeps
&lt;/h2&gt;

&lt;p&gt;Whether you're rotating wallets, archiving an old address, or just OCD about balance dust — this technique gives you full control.&lt;/p&gt;

&lt;p&gt;🧹 Clean wallet, clean mind.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As a prerequisite, you may want to review my earlier guide: &lt;a href="https://dev.to/rwu_security_researcher/how-to-fully-empty-a-wallet-via-chrome-console-without-leaving-dust-32nh"&gt;How to Fully Empty a Wallet via Chrome Console Without Leaving Dust&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>metamask</category>
      <category>erc20</category>
      <category>web3</category>
    </item>
    <item>
      <title>Learn Solidity Through Code: Breaking Down Walkthrough.sol Step by Step</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Sun, 04 May 2025 17:35:55 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/learn-solidity-through-code-breaking-down-walkthroughsol-step-by-step-bhf</link>
      <guid>https://dev.to/rwu_security_researcher/learn-solidity-through-code-breaking-down-walkthroughsol-step-by-step-bhf</guid>
      <description>&lt;p&gt;If you're starting your journey into Solidity and smart contract development, diving into actual code can be one of the most effective ways to learn. In this guide, we'll dissect Walkthrough.sol, a simple yet insightful smart contract, to understand how Solidity works in practice.&lt;/p&gt;

&lt;p&gt;🔍 What Is Walkthrough.sol?&lt;br&gt;
Walkthrough.sol is a Solidity contract designed to guide learners through various functions and concepts. It includes state variables, constructors, pure functions, and string comparisons using hashing. By analyzing this contract, you'll gain a hands-on understanding of how smart contracts operate on the Ethereum blockchain.&lt;/p&gt;

&lt;p&gt;📜 The Walkthrough Contract — Full Source&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Walkthrough {
    string public password;
    uint8 public infoNum = 42;
    string public theMethodName = "The method name is method7123949.";
    bool private cleared = false;

    constructor(string memory _password) {
        password = _password;
    }

    function info() public pure returns (string memory) {
        return "You will find what you need in info1().";
    }

    function info1() public pure returns (string memory) {
        return 'Try info2(), but with "hello" as a parameter.';
    }

    function info2(string memory param) public pure returns (string memory) {
        if (keccak256(abi.encodePacked(param)) == keccak256(abi.encodePacked("hello"))) {
            return "The property infoNum holds the number of the next info method to call.";
        }
        return "Wrong parameter.";
    }

    function info42() public pure returns (string memory) {
        return "theMethodName is the name of the next method.";
    }

    function method7123949() public pure returns (string memory) {
        return "If you know the password, submit it to authenticate().";
    }

    function authenticate(string memory passkey) public {
        if (keccak256(abi.encodePacked(passkey)) == keccak256(abi.encodePacked(password))) {
            cleared = true;
        }
    }

    function getCleared() public view returns (bool) {
        return cleared;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧱 Contract Structure and Components&lt;br&gt;
Let's examine the contract piece by piece.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pragma Directive and Contract Declaration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Walkthrough {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;pragma solidity ^0.8.0;: Specifies that the contract is written for Solidity version 0.8.0 or higher.&lt;/li&gt;
&lt;li&gt;contract Walkthrough {: Begins the definition of the contract named Walkthrough.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  State Variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    string public password;
    uint8 public infoNum = 42;
    string public theMethodName = "The method name is method7123949.";
    bool private cleared = false;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;string public password;: Declares a public string variable to store the password.&lt;/li&gt;
&lt;li&gt;uint8 public infoNum = 42;: Initializes a public unsigned integer with the value 42.&lt;/li&gt;
&lt;li&gt;string public theMethodName = "The method name is method7123949.";: Stores a string indicating the name of a method.&lt;/li&gt;
&lt;li&gt;bool private cleared = false;: A private boolean flag initialized to false.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Constructor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    constructor(string memory _password) {
        password = _password;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purpose: Sets the initial password when the contract is deployed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Informational Functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function info() public pure returns (string memory) {
        return "You will find what you need in info1().";
    }

    function info1() public pure returns (string memory) {
        return 'Try info2(), but with "hello" as a parameter.';
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;info(): Returns a hint directing to info1().&lt;/li&gt;
&lt;li&gt;info1(): Suggests calling info2() with the parameter "hello".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conditional Function with Parameter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function info2(string memory param) public pure returns (string memory) {
        if (keccak256(abi.encodePacked(param)) == keccak256(abi.encodePacked("hello"))) {
            return "The property infoNum holds the number of the next info method to call.";
        }
        return "Wrong parameter.";
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purpose: Checks if the input parameter matches "hello" by comparing their hashes. If it matches, provides a hint; otherwise, returns an error message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Informational Functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function info42() public pure returns (string memory) {
        return "theMethodName is the name of the next method.";
    }

    function method7123949() public pure returns (string memory) {
        return "If you know the password, submit it to authenticate().";
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;info42(): Hints at the method name to call next.&lt;/li&gt;
&lt;li&gt;method7123949(): Instructs to use the password with the authenticate() function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function authenticate(string memory passkey) public {
        if (keccak256(abi.encodePacked(passkey)) == keccak256(abi.encodePacked(password))) {
            cleared = true;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purpose: Compares the hash of the input passkey with the stored password. If they match, sets cleared to true.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Check Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function success() public view returns (string memory) {
        require(cleared, "Not authenticated");
        return "Congratulations!";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purpose: Returns a success message if cleared is true; otherwise, reverts with "Not authenticated".&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Concepts Illustrated
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;State Variables: Understanding how to declare and initialize variables that store data on the blockchain.&lt;/li&gt;
&lt;li&gt;Constructors: Setting initial values during contract deployment.&lt;/li&gt;
&lt;li&gt;Function Visibility: Using public, private, and pure to control access and behavior.&lt;/li&gt;
&lt;li&gt;String Comparison: Employing keccak256 and abi.encodePacked for secure string comparisons.&lt;/li&gt;
&lt;li&gt;Conditional Logic: Implementing if statements and require for control flow and validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 Try It Yourself&lt;br&gt;
To reinforce your understanding, deploy and interact with Walkthrough.sol using the &lt;a href="https://remix.ethereum.org/" rel="noopener noreferrer"&gt;Remix IDE&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy the Contract: Input a password of your choice during deployment.&lt;/li&gt;
&lt;li&gt;Explore Functions: Call info(), info1(), and info2("hello") to follow the hints.&lt;/li&gt;
&lt;li&gt;Authenticate: Use the correct password with authenticate() to set cleared to true.&lt;/li&gt;
&lt;li&gt;Check Success: Call success() to see if you've successfully authenticated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Conclusion&lt;br&gt;
By stepping through Walkthrough.sol, you've explored fundamental Solidity concepts in a practical context. This hands-on approach demystifies how smart contracts function and lays the groundwork for more advanced learning.&lt;/p&gt;

&lt;p&gt;Feel free to experiment further by modifying the contract, adding new functions, or integrating it with other contracts to deepen your understanding.&lt;/p&gt;

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

</description>
      <category>solidity</category>
      <category>ethereum</category>
      <category>cryptocurrency</category>
      <category>programming</category>
    </item>
    <item>
      <title>12-Word Seed Phrase Posted on YouTube ?? It Was a Trap.</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Thu, 01 May 2025 18:40:54 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/12-words-secret-seed-phrase-on-youtube-it-was-a-trap-2lmb</link>
      <guid>https://dev.to/rwu_security_researcher/12-words-secret-seed-phrase-on-youtube-it-was-a-trap-2lmb</guid>
      <description>&lt;p&gt;On May 1, 2025, I came across a YouTube comment that looked innocent — maybe even a little desperate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Thanks for sharing such valuable information! Just a quick off-topic question: My OKX wallet holds some USDT, and I have the seed phrase... What's the best way to send them to Binance?"— @RosiVanadis, YouTube comment&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The message even included a full 12-word seed phrase, casually posted in public. To a greedy or curious onlooker, it might seem like someone just gave away free money — a forgotten wallet with tokens still inside.&lt;/p&gt;

&lt;p&gt;But if you've been in crypto long enough, your instinct should be to pause. This wasn’t carelessness. It might be bait.&lt;/p&gt;

&lt;h1&gt;
  
  
  Investigating the Wallet
&lt;/h1&gt;

&lt;p&gt;Based on the seed phrase posted in the YouTube comment, the derived Ethereum address is 0xc6D71Cc477DFc5Fe0b0Dd8e93De620447880D52E. &lt;/p&gt;

&lt;p&gt;The last two transactions include one it received 0.0441 ETH from a MoonPay-labeled address. Immediately afterward, the ETH was emptied out to another address &lt;a href="https://etherscan.io/address/0x00001f9d06dce5c2d30a03396405e8d071434001" rel="noopener noreferrer"&gt;https://etherscan.io/address/0x00001f9d06dce5c2d30a03396405e8d071434001&lt;/a&gt;. Both transactions happened at the exact second (Apr-29-2025 11:07:47 AM UTC).&lt;/p&gt;

&lt;p&gt;It could be bait. And even if it isn’t, you have no way of knowing what traps may be set — financially or technically.&lt;/p&gt;

&lt;p&gt;But one thing is unclear: why would someone send ETH to a wallet that appears empty? If this was bait, there was no visible token or value in the address to lure a victim. This raises the possibility that the sender and the trap operator might be the same entity — perhaps testing automated sweeping logic or tracking wallet monitoring infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigating the Withdrawal Address
&lt;/h2&gt;

&lt;p&gt;The destination of the swept ETH — 0x00001f9d06dce5c2d30a03396405e8d071434001 — appears to be a vanity address, possibly generated to seem benign or system-generated. Initial inspection of the address on Etherscan shows multiple incoming transfers from other compromised-looking wallets, all drained within seconds of receiving ETH. This strongly suggests it's part of a botnet or a coordinated draining infrastructure. Further clustering analysis could reveal other scam wallets it interacts with.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Safely Analyze a Public Seed Phrase
&lt;/h2&gt;

&lt;p&gt;If you encounter a public 12-word seed phrase and want to investigate it without risk:&lt;/p&gt;

&lt;p&gt;Use a trusted local environment:&lt;br&gt;
Run the following command after installing Node.js and the ethers library (v6 or later):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -e "import('ethers').then(e =&amp;gt; console.log(e.HDNodeWallet.fromPhrase('your twelve words here').address))"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste the phrase into web wallets or browser extensions. These may accidentally connect to live networks or leak data.&lt;/p&gt;

&lt;p&gt;Check the wallet on a public explorer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paste the derived address into Etherscan&lt;/li&gt;
&lt;li&gt;Look for unusual transaction patterns (instant sweeps, repeated funding, identical gas usage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t interact with the wallet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never send ETH to it&lt;/li&gt;
&lt;li&gt;Never call smart contract functions from it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these steps, you can safely study traps and better understand how attackers structure their scams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay curious. Stay skeptical. Stay safe.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>security</category>
      <category>mev</category>
    </item>
    <item>
      <title>The Ethereum Pectra Upgrade</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Wed, 30 Apr 2025 10:33:59 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/the-ethereum-pectra-upgrade-144j</link>
      <guid>https://dev.to/rwu_security_researcher/the-ethereum-pectra-upgrade-144j</guid>
      <description>&lt;p&gt;The Ethereum Pectra upgrade combines two major protocol updates: the Prague execution layer and the Electra consensus layer. Scheduled for mainnet activation on May 7, 2025, Pectra introduces a variety of changes aimed at improving validator efficiency, data handling, and developer flexibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Improvements in the Pectra Upgrade
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Enhanced Validator Flexibility
&lt;/h3&gt;

&lt;p&gt;EIP-7251: Increases the maximum effective balance for validators from 32 ETH to 2,048 ETH, and you can stake any amount between 32 and 2,048 ETH per validator. This change allows validators to consolidate their stakes, reducing the number of validators.​&lt;/p&gt;

&lt;p&gt;EIP-6110: Moves validator deposit processing fully on-chain, simplifying infrastructure and improving transparency.&lt;/p&gt;

&lt;p&gt;EIP-7002: Enables validator withdrawals to be initiated by smart contracts, allowing for flexible and automated staking services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability and Data Availability Enhancements
&lt;/h3&gt;

&lt;p&gt;EIP-7691: Increases the number of data blobs per block, aiming to improve data availability for Layer 2 solutions. While this may help reduce L2 transaction costs, it also raises concerns about whether Ethereum’s base layer is adequately compensated in a rollup-centric model.&lt;/p&gt;

&lt;p&gt;EIP-7685: Introduces a general-purpose framework for structured communication between Ethereum’s execution and consensus layers. This aims to simplify protocol upgrades, though its impact is mostly architectural.&lt;/p&gt;

&lt;h3&gt;
  
  
  Account Abstraction and Smart Contract Usability
&lt;/h3&gt;

&lt;p&gt;EIP-7702: Allows externally owned accounts (EOAs) to temporarily act like smart contracts during a transaction. This enables advanced features such as batching, sponsor-paid gas fees, and session-based signing — without requiring full account abstraction.&lt;/p&gt;

&lt;p&gt;EIP-2935: Stores historical block hashes in persistent state, improving support for smart contracts that rely on older block references (e.g., randomness, delayed proofs).&lt;/p&gt;

&lt;h2&gt;
  
  
  Implications for Developers and Stakers
&lt;/h2&gt;

&lt;p&gt;No immediate action is required from ETH holders. However, developers and validator operators should familiarize themselves with the changes to benefit from improved staking mechanics, increased flexibility in account behavior, and enhanced infrastructure for Layer 2 and protocol upgrades.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>eip</category>
      <category>web3</category>
    </item>
    <item>
      <title>Tracing April 2025 Bitcoin Movements and Monero Surge</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Tue, 29 Apr 2025 12:41:19 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/tracing-april-2025-bitcoin-movements-and-monero-surge-p44</link>
      <guid>https://dev.to/rwu_security_researcher/tracing-april-2025-bitcoin-movements-and-monero-surge-p44</guid>
      <description>&lt;p&gt;Blockchain investigator ZachXBT reported that approximately 3,520 BTC (~$330M) were transferred from a suspicious address, coinciding with sharp Monero (XMR) price surges.&lt;/p&gt;

&lt;p&gt;According to his post, the stolen funds began to be laundered through six or more instant swap exchanges.&lt;/p&gt;

&lt;p&gt;As of this writing, no public disclosure of a specific hacked entity has been made.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Timeline of XMR-USD Events
&lt;/h2&gt;

&lt;p&gt;(All times are Eastern Time, New York)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~6:00 PM, April 27 (Sunday) — Initial Monero buying begins; volume starts increasing steadily.&lt;/li&gt;
&lt;li&gt;~9:25 PM, April 27 — XMR peaks at $303.23 after a gap jump, with peak dollar volume reaching $19.9M.&lt;/li&gt;
&lt;li&gt;~11:15 PM, April 27 — XMR drifts lower to $258.13, with significantly reduced trading volume.&lt;/li&gt;
&lt;li&gt;~1:50 AM, April 28 (Monday) — Price surges to a high of $339.19. The move involves eight rounds of violent upward and downward swings, with each push accompanied by $10M–$20M in dollar volume.&lt;/li&gt;
&lt;li&gt;~5:10 AM, April 28 — The majority of large whale-driven trading ends; the price drifts down to $261.81.&lt;/li&gt;
&lt;li&gt;~5:10 PM, April 28 — The session low is recorded at $250.59.&lt;/li&gt;
&lt;li&gt;~7:31 AM, April 29 — XMR drifts higher toward the $270s with significantly lower trading volume.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While total observed trading volume during the XMR spikes exceeded $120M, estimates of net laundering activity suggest approximately $50M worth of Bitcoin was converted during the active window.&lt;/p&gt;

&lt;p&gt;🧱 Realistic Analysis of Timing and Liquidity&lt;/p&gt;

&lt;h2&gt;
  
  
  Weekend liquidity is always lower — but that's a double-edged sword
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Market makers and OTC desks are mostly offline Friday night to Sunday night.&lt;/li&gt;
&lt;li&gt;Order books are thinner.&lt;/li&gt;
&lt;li&gt;Slippage is worse.&lt;/li&gt;
&lt;li&gt;The small laundering operations pays heavy price premiums. In this case, the bad actors accepted 30%–40% effective loss to achieve fast laundering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The massive Monero spikes (~$220 → ~$339) almost certainly triggered automated tracking (whale bots, security firms, alert systems). Their urgency outweighed their stealth — they tried to race against the clock but sacrificed stealth by causing huge market waves.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Strategic Conclusion
&lt;/h2&gt;

&lt;p&gt;✅ Their operational goal was clear: "Finish laundering by early Monday before compliance desks activate."&lt;br&gt;
✅ But their execution quality was poor, and they overpaid massively (likely 30%–40%) for privacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monero’s Privacy Mechanisms
&lt;/h2&gt;

&lt;p&gt;Monero was engineered from its inception to achieve strong on-chain privacy through multiple integrated technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ring Signatures: Hide the sender by mixing each transaction input with multiple decoys.&lt;/li&gt;
&lt;li&gt;Stealth Addresses: Generate one-time destination addresses for each transaction, protecting the receiver’s identity.&lt;/li&gt;
&lt;li&gt;Confidential Transactions (RingCT): Conceal transaction amounts, preventing external observers from inferring transaction details.&lt;/li&gt;
&lt;li&gt;Dandelion++: Obfuscate network-level metadata such as IP addresses during transaction propagation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike other chains where privacy must be consciously enabled or externally added, &lt;strong&gt;Monero applies privacy protections by default at the protocol level.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From a purely technical standpoint, Monero consistently fulfills its stated design goal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enabling private, untraceable, and unlinkable transactions on a public ledger.&lt;/li&gt;
&lt;li&gt;Chain analysis techniques that work against Bitcoin or Ethereum are ineffective against Monero’s design.&lt;/li&gt;
&lt;li&gt;Transaction flows, participant addresses, and transferred amounts are fundamentally shielded from public scrutiny.&lt;/li&gt;
&lt;li&gt;Privacy is enforced at both the ledger and network communication layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Forensic investigation of the address &lt;a href="https://www.blockchain.com/explorer/addresses/btc/bc1qcrypchnrdx87jnal5e5m849fw460t4gk7vz55g" rel="noopener noreferrer"&gt;bc1qcrypchnrdx87jnal5e5m849fw460t4gk7vz55g&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Address type  Bech32 (P2WPKH) — standard Bitcoin SegWit address&lt;/li&gt;
&lt;li&gt;Balance now   Basically empty — only 0.00000846 BTC (~$0.80) left&lt;/li&gt;
&lt;li&gt;Total received    7017.53874053 BTC (~$667M)&lt;/li&gt;
&lt;li&gt;Total sent    7017.53873207 BTC (~$667M)&lt;/li&gt;
&lt;li&gt;Transactions  8 transactions total&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ This address handled enormous sums in a very short time, and then was fully drained.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transaction timeline
&lt;/h2&gt;

&lt;p&gt;4/27/2025 ~17:01–17:15 (New York Time)&lt;/p&gt;

&lt;p&gt;Received large deposits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;70 BTC (~$6.7M)&lt;/li&gt;
&lt;li&gt;3,450 BTC (~$327M)
(→ total ~3,520 BTC — matches ZachXBT post.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4/27/2025 ~17:11–17:37&lt;/p&gt;

&lt;p&gt;Started draining the address:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sent ~63 BTC&lt;/li&gt;
&lt;li&gt;Sent ~310 BTC&lt;/li&gt;
&lt;li&gt;Sent ~2789 BTC&lt;/li&gt;
&lt;li&gt;Sent ~357 BTC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4/28/2025 ~04:26 AM&lt;/p&gt;

&lt;p&gt;Minor dust transaction (insignificant).&lt;/p&gt;

&lt;p&gt;✅ Right after receiving 3,520 BTC, the hacker broke it apart and flushed out to multiple addresses.&lt;/p&gt;

&lt;p&gt;Timing exactly matches Monero spike beginning (~6PM NYT Sunday → early Monday).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;p&gt;Further developments, including forensic reports or exchange investigations, may refine our understanding of this event over time.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>privacy</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>How to Fully Empty a Wallet via Chrome Console Without Leaving Dust</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Tue, 29 Apr 2025 02:53:46 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/how-to-fully-empty-a-wallet-via-chrome-console-without-leaving-dust-32nh</link>
      <guid>https://dev.to/rwu_security_researcher/how-to-fully-empty-a-wallet-via-chrome-console-without-leaving-dust-32nh</guid>
      <description>&lt;p&gt;When transferring your full ETH balance from one wallet to another, most wallets leave a tiny amount of "dust" behind. This happens because they slightly overestimate gas fees to prevent transaction failure under volatile conditions.&lt;/p&gt;

&lt;p&gt;But sometimes, you want &lt;strong&gt;zero&lt;/strong&gt; balance left — no dust, no leftovers — for example, when migrating to a new wallet, shutting down an address, or sweeping all funds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how you can do it perfectly, using only MetaMask and Chrome console.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 Step-by-Step Instructions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open your Chrome browser.&lt;/li&gt;
&lt;li&gt;Unlock your MetaMask extension.&lt;/li&gt;
&lt;li&gt;Transfer all valuable tokens, NFTs, and other assets&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;DevTools&lt;/strong&gt; → &lt;strong&gt;Console&lt;/strong&gt; tab (&lt;code&gt;F12&lt;/code&gt; or &lt;code&gt;Ctrl+Shift+I&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Paste and &lt;strong&gt;REPLACE the RECEIVER address as you intended&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Execute the following script:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_requestAccounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}))[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xReceiverAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c1"&gt;// 🔥 Change this to your destination address&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balanceHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_getBalance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gasPriceHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_gasPrice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gasLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Standard gas for basic ETH transfer&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gasFee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gasPriceHex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gasLimit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balanceHex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amountToSend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;gasFee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amountToSend&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not enough balance to cover gas fee.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_sendTransaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;amountToSend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;gas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gasLimit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;gasPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gasPriceHex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transaction sent! TxHash:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm the transaction in MetaMask popup.&lt;/p&gt;

&lt;p&gt;✅ Done! Your account will now be completely emptied.&lt;/p&gt;

&lt;p&gt;🧠 Why Not Just Use Wallet UI?&lt;/p&gt;

&lt;p&gt;Wallet UIs like MetaMask intentionally overestimate gas fees to reduce transaction failure risks.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;They cannot send the full balance.&lt;/li&gt;
&lt;li&gt;They must leave a small "dust" amount as a safety margin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By manually calculating gas cost and subtracting it ourselves, we can send the maximum possible safely.&lt;/p&gt;

&lt;p&gt;📝 Why I Care About This&lt;/p&gt;

&lt;p&gt;When EIP-1559 was introduced, dynamic fees made gas price calculations trickier, and wallets became even more conservative.&lt;/p&gt;

&lt;p&gt;I often found myself frustrated by the "dust problem" when I simply wanted to sweep a wallet clean. This method helped me move entire balances safely and efficiently, many times over.&lt;/p&gt;

&lt;p&gt;Feel free to bookmark this guide for the next time you need a clean sweep. 🧹✨&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>web3</category>
      <category>javascript</category>
      <category>metamask</category>
    </item>
    <item>
      <title>Demystifying Reentrancy Attacks in Solidity: Vulnerabilities and Defenses</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Mon, 28 Apr 2025 20:00:47 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/demystifying-reentrancy-attacks-in-solidity-vulnerabilities-and-defenses-3ofk</link>
      <guid>https://dev.to/rwu_security_researcher/demystifying-reentrancy-attacks-in-solidity-vulnerabilities-and-defenses-3ofk</guid>
      <description>&lt;h2&gt;
  
  
  The vulnerable service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ServiceContract {
  mapping(address =&amp;gt; uint) public balances;

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

  function withdraw() external {
    uint balance = balances[msg.sender];
    require(balance &amp;gt; 0, "No funds");
    // ❌ Vulnerable: external call before state update
    (bool sent, ) = msg.sender.call{value: balance}("");
    require(sent, "Failed");
    balances[msg.sender] = 0;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Business Scenario
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fieiwvk5en7jp5v20ij21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fieiwvk5en7jp5v20ij21.png" alt="The interaction between the client and the service" width="800" height="533"&gt;&lt;/a&gt; The service contract is like a bank, holding the assets for the clients. When a client deposit &lt;code&gt;msg.value&lt;/code&gt; the ETH, it records the balance in the ledger balances. When the clients withdraws,  it checks the ledger balance, and sends &lt;code&gt;msg.sender&lt;/code&gt; all the balance with the assumption the client will do nothing when receiving this fund, and clears the ledger thereafter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The malicious client
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ClientContract {
  ServiceContract public service;
  constructor(address _service) { 
    service = ServiceContract(_service); 
  }

  // Kick off the attack
  function attack() external payable {
    require(msg.value &amp;gt;= 1 ether);
    service.deposit{value: msg.value}();
    service.withdraw();
  }

  fallback() external payable {
    if (address(service).balance &amp;gt;= 1 ether) {
      service.withdraw();  // reenter!
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client is not regular client, but a client who exploits the logic vulnerability of the service, when it receives funds through the fallback() function, it will initiate a new withdraw() request as long as the ledger is stale and validate the withdraw, it got the balance of the service contract, i.e. a lot of third party clients' money until it falls below 1 ETH.&lt;/p&gt;

&lt;p&gt;Defenses against the reentrance attack&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✔️ Checks–Effects–Interactions
function safeWithdraw() external {
    uint balance = balances[msg.sender];
    require(balance &amp;gt; 0, "No funds");
    balances[msg.sender] = 0; // effect first
    (bool sent, ) = msg.sender.call{value: balance}("");
    require(sent, "Failed");
}

// ✔️ Using ReentrancyGuard
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract GuardedService is ReentrancyGuard {
    mapping(address=&amp;gt;uint) public balances;

    // deposit() same...
    function withdraw() external nonReentrant {
        uint balance = balances[msg.sender];
        require(balance&amp;gt;0);
        balances[msg.sender]=0;
        (bool sent,)=msg.sender.call{value:balance}("");
        require(sent);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why the client uses the fallback() function instead of the receive() function directly to execute a reentrancy attack. &lt;/p&gt;

&lt;p&gt;The receive() function is invoked when a contract receives Ether without any data (i.e., via send() or transfer()). These methods forward only 2300 gas, which is insufficient for complex operations like re-entering another contract. Conversely, call{value: amount}("") forwards all remaining gas, allowing the fallback() function to execute more complex logic, including reentrant calls.&lt;/p&gt;

&lt;p&gt;Unsafe transfer method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payable(msg.sender).call{value: amount}(""); // UNSAFE!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attacker’s receive() can execute further calls, allowing reentrancy.&lt;/p&gt;

&lt;p&gt;Safe transfer methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payable(msg.sender).transfer(amount); // safe (2300 gas)
payable(msg.sender).send(amount);     // safe (2300 gas, but check 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attacker’s receive() function will fail if it tries any logic beyond simple logging or receiving funds due to the low gas limit.&lt;/p&gt;

&lt;p&gt;A regular client address (EOA—Externally Owned Account) that does not have a contract cannot execute code upon receiving Ether. Only a contract can execute logic automatically upon receiving Ether.&lt;/p&gt;

&lt;p&gt;Please try it yourself at &lt;a href="https://ethernaut.openzeppelin.com/level/10" rel="noopener noreferrer"&gt;https://ethernaut.openzeppelin.com/level/10&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidity</category>
      <category>evm</category>
      <category>ethereum</category>
      <category>web3</category>
    </item>
    <item>
      <title>Smart Contracts Deep Dive: Storage Packing, Payment Flows, and msg Object Explained</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Sun, 27 Apr 2025 14:58:18 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/smart-contracts-deep-dive-storage-packing-payment-flows-and-msg-object-explained-4b8e</link>
      <guid>https://dev.to/rwu_security_researcher/smart-contracts-deep-dive-storage-packing-payment-flows-and-msg-object-explained-4b8e</guid>
      <description>&lt;p&gt;In my last article, "&lt;a href="https://dev.to/rwu_security_researcher/inside-a-smart-contract-storage-execution-and-blockchain-behavior-1g9l"&gt;Inside a Smart Contract: Storage, Execution, and Blockchain Behavior&lt;/a&gt;", we explored how smart contracts store data, execute logic, and interact with the blockchain.&lt;/p&gt;

&lt;p&gt;Today, we are diving deeper into three fundamental aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Solidity optimizes storage with Storage Packing&lt;/li&gt;
&lt;li&gt;How smart contracts handle Receiving and Sending Payments&lt;/li&gt;
&lt;li&gt;Understanding the msg object (msg.sender, msg.value, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll also build a complete smart contract example that ties all these concepts together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solidity Storage Packing: Saving Gas by Using Less Space
&lt;/h2&gt;

&lt;p&gt;In the Ethereum Virtual Machine (EVM), storage is divided into slots of 32 bytes (256 bits).&lt;/p&gt;

&lt;p&gt;Storage Packing happens when Solidity fits multiple small variables into a single storage slot to save space and gas.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Good packing: fits into 1 slot
uint128 a; // 16 bytes
uint128 b; // 16 bytes

// Bad packing: takes 2 slots
uint128 a;
uint256 b;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variables are packed in order of declaration.&lt;/li&gt;
&lt;li&gt;Types must fit without overflowing the 32-byte limit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why it matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage on Ethereum is very expensive.&lt;/li&gt;
&lt;li&gt;Fewer slots = lower gas fees = cheaper transactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real Storage Layout Example&lt;/p&gt;

&lt;p&gt;Suppose we store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = 0xAAAA (uint128)
b = 0xBBBB (uint128)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good Packing Storage (Single Slot):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Slot 0: 0x000...BBBB...AAAA
Higher 16 bytes: BBBB
Lower 16 bytes: AAAA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bad Packing Storage (Two Slots):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Slot 0: 0x000...0000...AAAA
Slot 1: 0x000...0000...BBBB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notice how the badly packed version wastes a whole extra slot!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment Flows: Receiving and Sending ETH/Tokens
&lt;/h2&gt;

&lt;p&gt;Smart contracts can receive and send ETH and tokens. Handling these flows properly is critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving ETH
&lt;/h3&gt;

&lt;p&gt;Use the receive() or fallback() function, and they must be marked payable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;receive() external payable {
    // Handle ETH received
}

fallback() external payable {
    // Handle unexpected calls
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sending ETH
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Using transfer
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function basicTransferETH(address payable recipient, uint256 amount) external {
    require(address(this).balance &amp;gt;= amount, "Insufficient balance");
    recipient.transfer(amount);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For developers with an OOP background, recipient.transfer(amount) might look like a method call on the recipient object. However, in Solidity, it actually means "send ETH from this contract to the recipient" — it is still this contract that is initiating the transfer using its own balance.&lt;/p&gt;

&lt;p&gt;Transfers ETH and reverts on failure. Sends exactly 2300 gas, enough only to emit an event. The transfer automatically reverts if the recipient's fallback function consumes more than 2300 gas.&lt;/p&gt;

&lt;p&gt;Therefore, while transfer looks simple, it can be surprisingly fragile in real-world scenarios.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using send
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function basicSendETH(address payable recipient, uint256 amount) external {
    require(address(this).balance &amp;gt;= amount, "Insufficient balance");
    bool success = recipient.send(amount);
    require(success, "Failed to send Ether");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;send() returns a boolean indicating success or failure; it does not automatically revert like transfer().&lt;br&gt;
It also only forwards 2300 gas.&lt;br&gt;
You must manually handle failure by checking the return value.&lt;/p&gt;
&lt;h4&gt;
  
  
  Using call safely
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function safeTransferETH(address payable recipient, uint256 amount) external payable {
    require(address(this).balance &amp;gt;= amount, "Insufficient balance");
    (bool sent, ) = recipient.call{value: amount}("");
    require(sent, "Failed to send Ether");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;ul&gt;
&lt;li&gt;You ensure there is enough balance.&lt;/li&gt;
&lt;li&gt;You check the result of call to confirm success.&lt;/li&gt;
&lt;li&gt;You avoid gas limitation issues that might arise from transfer or send.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Sending ERC20 Tokens
&lt;/h3&gt;

&lt;p&gt;In modern Solidity (0.8.x), &lt;code&gt;transfer&lt;/code&gt; returns a boolean. Always capture and check the return value to ensure the transfer succeeded, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bool success = IERC20(tokenAddress).transfer(to, amount);
require(success, "Token transfer failed");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids mistakenly believing a transfer occurred when it failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The msg Object: Your Contract's Context
&lt;/h2&gt;

&lt;p&gt;The msg object contains important metadata about the current transaction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;msg.sender — who initiated the call (an EOA or another contract)&lt;/li&gt;
&lt;li&gt;msg.value — how much ETH (in wei) was sent with the transaction&lt;/li&gt;
&lt;li&gt;msg.data — the full calldata&lt;/li&gt;
&lt;li&gt;msg.sig — the 4-byte function selector
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function pay() public payable {
    require(msg.value &amp;gt; 0, "No ETH sent");
    address payer = msg.sender;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If Contract A calls Contract B, then inside B, msg.sender is A, not the original user.&lt;/li&gt;
&lt;li&gt;Be cautious using tx.origin; it can expose your contract to phishing attacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Full Smart Contract Example
&lt;/h2&gt;

&lt;p&gt;Here is a full Solidity contract that showcases all these concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
}

contract DeepDiveContract {
    // ❌ Bad storage packing
    uint128 bigNumber;
    uint256 veryBigNumber;

    // ✅ Good storage packing
    uint128 smallA;
    uint128 smallB;

    // Events
    event Received(address sender, uint256 amount, bytes data, bytes4 sig);
    event PaymentSent(address recipient, uint256 amount);
    event TokenSent(address recipient, uint256 amount, address tokenAddress);

    // Receiving ETH
    receive() external payable {
        emit Received(msg.sender, msg.value, msg.data, msg.sig);
    }

    fallback() external payable {
        emit Received(msg.sender, msg.value, msg.data, msg.sig);
    }

    // Sending ETH
    function sendEther(address payable _to) external payable {
        require(msg.value &amp;gt; 0, "Send some ETH to forward");
        (bool sent, ) = _to.call{value: msg.value}("");
        require(sent, "Failed to send Ether");
        emit PaymentSent(_to, msg.value);
    }

    // Sending ERC20 Tokens
    function sendToken(address tokenAddress, address to, uint256 amount) external {
        bool success = IERC20(tokenAddress).transfer(to, amount);
        require(success, "Token transfer failed");
        emit TokenSent(to, amount, tokenAddress);
    }

    // Write to bad storage
    function writeBadStorage(uint128 _bigNumber, uint256 _veryBigNumber) external {
        bigNumber = _bigNumber;
        veryBigNumber = _veryBigNumber;
    }

    // Write to good storage
    function writeGoodStorage(uint128 _smallA, uint128 _smallB) external {
        smallA = _smallA;
        smallB = _smallB;
    }

    // View bad storage
    function viewBadStorage() external view returns (uint128, uint256) {
        return (bigNumber, veryBigNumber);
    }

    // View good storage
    function viewGoodStorage() external view returns (uint128, uint128) {
        return (smallA, smallB);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Storage optimization saves gas.&lt;br&gt;
Correctly managing ETH and token flows prevents losing funds.&lt;br&gt;
Understanding msg.sender and related metadata is critical for secure smart contract programming.&lt;/p&gt;

&lt;p&gt;Mastering these fundamentals prepares you for designing secure, efficient, and upgradeable smart contracts.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>solidity</category>
      <category>ethereum</category>
      <category>evm</category>
    </item>
    <item>
      <title>Inside a Smart Contract: Storage, Execution, and Blockchain Behavior</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Sun, 27 Apr 2025 01:04:41 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/inside-a-smart-contract-storage-execution-and-blockchain-behavior-1g9l</link>
      <guid>https://dev.to/rwu_security_researcher/inside-a-smart-contract-storage-execution-and-blockchain-behavior-1g9l</guid>
      <description>&lt;p&gt;Let us deploy this contract to Sepolia Testnet using Chrome console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ExecutionExplorer {
    uint256 public storedValue;
    address public lastSender;
    uint256 public callCount;

    event ValueUpdated(uint256 newValue, address indexed updater);

    constructor(uint256 initialValue) {
        storedValue = initialValue;
        lastSender = msg.sender;
        callCount = 0;
    }

    function updateValue(uint256 newValue) external {
        storedValue = newValue;
        lastSender = msg.sender;
        callCount += 1;

        emit ValueUpdated(newValue, msg.sender);
    }

    function getContractBalance() external view returns (uint256) {
        return address(this).balance;
    }

    receive() external payable {} // Accept ETH
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the Compiled Bytecode from Remix&lt;/p&gt;

&lt;p&gt;If you forget how to get it, please read &lt;a href="https://dev.to/rwu_security_researcher/from-source-to-blockchain-how-smart-contracts-go-live-with-remix-and-metamask-25h8"&gt;https://dev.to/rwu_security_researcher/from-source-to-blockchain-how-smart-contracts-go-live-with-remix-and-metamask-25h8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Chrome Console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// The Compile Bytecode from remix&lt;/span&gt;
&lt;span class="c1"&gt;// const bytecode = "0x608060405234801561000f575f80fd5b506...";&lt;/span&gt;

&lt;span class="c1"&gt;// We need to encode the constructor argument &lt;/span&gt;
&lt;span class="c1"&gt;// into 32-byte ABI format.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hexString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;hexString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hexString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;constructorArg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hexString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Combine&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deploymentData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bytecode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;constructorArg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to MetaMask&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_requestAccounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_accounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Prepare deployment transaction&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deploymentData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x2dc6c0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// (optional) 200,000 gas&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Send transaction&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_sendTransaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;txParams&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deployment Transaction Hash:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MetaMask pops up, asks you to confirm.&lt;/p&gt;

&lt;p&gt;This becomes just a pending transaction — floating in the mempool of your network. Validators pick transactions from the mempool to include in the next block after simulating them.&lt;/p&gt;

&lt;p&gt;A validator (Proof of Stake) picks up your transaction and simulate the transaction locally using the EVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They run your deploymentData as code in their private EVM simulation.&lt;/li&gt;
&lt;li&gt;If execution succeeds without errors (and gas is sufficient):

&lt;ul&gt;
&lt;li&gt;The blockchain engine creates a new contract address.&lt;/li&gt;
&lt;li&gt;The runtime bytecode, i.e. the remix bytecode inside the deploymentData without the argumentData is stored at that address.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Your storedValue, lastSender, callCount variables are set into storage in the private EVM simulation.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;🎯 If anything fails (out of gas, bad opcode, etc.), the whole transaction reverts — nothing is deployed.&lt;/p&gt;

&lt;p&gt;After the validator successfully simulates and commits the block:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The new contract is officially created on-chain.&lt;/li&gt;
&lt;li&gt;Your storedValue is truly set to 42 — and the world agrees on that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠 How to confirm Raw Smart Contract Storage in Chrome Console after the deployment&lt;/p&gt;

&lt;p&gt;In Solidity, each public or internal variable is stored in a sequential "slot" in storage.&lt;/p&gt;

&lt;p&gt;Slot 0 → first variable (storedValue)&lt;br&gt;
Slot 1 → second variable (lastSender)&lt;br&gt;
Slot 2 → third variable (callCount)&lt;/p&gt;

&lt;p&gt;You want to check slot 0.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sepolia.etherscan.io/tx/0x37423eaf6aca4e8843fe5efbe62e79ac0e58dfcd47d09c50db0fdf28a2d759ac" rel="noopener noreferrer"&gt;https://sepolia.etherscan.io/tx/0x37423eaf6aca4e8843fe5efbe62e79ac0e58dfcd47d09c50db0fdf28a2d759ac&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x9B45d1AAF6e91C818F416e1D948A24962A26EF7a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Slot 0 for storedValue&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eth_getStorageAt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Stored value (raw hex):&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Stored value (parsed int):&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ This reads directly from Ethereum storage at the contract address!&lt;/p&gt;




&lt;p&gt;In this walkthrough, we focused on deploying a contract and verifying its initial storage.&lt;/p&gt;

&lt;p&gt;In the next article, we'll dive deeper — reading multiple storage slots, checking the contract's balance, and testing how it can receive ETH dynamically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned!
&lt;/h2&gt;

</description>
      <category>ethereum</category>
      <category>solidity</category>
      <category>web3</category>
      <category>evm</category>
    </item>
    <item>
      <title>From Source to Blockchain: How Smart Contracts Go Live with Remix and MetaMask</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Fri, 25 Apr 2025 21:48:16 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/from-source-to-blockchain-how-smart-contracts-go-live-with-remix-and-metamask-25h8</link>
      <guid>https://dev.to/rwu_security_researcher/from-source-to-blockchain-how-smart-contracts-go-live-with-remix-and-metamask-25h8</guid>
      <description>&lt;p&gt;Writing a smart contract is only the beginning. What happens between your source code and a live contract on the blockchain? In this article, we walk through the process with a clear road map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Counter {
    uint256 public count;

    function increment() public {
        count += 1;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Remix to compile
&lt;/h2&gt;

&lt;p&gt;If you are not familiar with Remix, please read &lt;a href="https://dev.to/rwu_security_researcher/demystifying-solidity-a-step-by-step-guide-using-walkthroughsol-2in6"&gt;Remix Walk Through&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;After compilation, you can access the ABI and bytecode of the contract from &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazpb054t9uxh8ntj8unq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazpb054t9uxh8ntj8unq.png" alt="ABI and Bytecode" width="178" height="49"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  ABI (Application Binary Interface)
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "inputs": [],
        "name": "count",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "increment",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The ABI tells the outside world &lt;strong&gt;how to interact with your smart contract&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s basically a &lt;strong&gt;contract blueprint&lt;/strong&gt; in JSON format. It lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The functions your contract exposes&lt;/li&gt;
&lt;li&gt;The input and output types&lt;/li&gt;
&lt;li&gt;Whether a function is &lt;code&gt;view&lt;/code&gt;, &lt;code&gt;pure&lt;/code&gt;, or payable&lt;/li&gt;
&lt;li&gt;Event declarations&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Bytecode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;6080604052348015600e575f80fd5b506101468061001c5f395ff3fe608060405
234801561000f575f80fd5b5060043610610034575f3560e01c806306661abd14
610038578063d09de08a14610056575b5f80fd5b610040610060565b604051610
04d9190610097565b60405180910390f35b61005e610065565b005b5f5481565b
60015f8082825461007691906100dd565b92505081905550565b5f81905091905
0565b6100918161007f565b82525050565b5f6020820190506100aa5f83018461
0088565b92915050565b7f4e487b7100000000000000000000000000000000000
0000000000000000000005f52601160045260245ffd5b5f6100e78261007f565b
91506100f28361007f565b925082820190508082111561010a576101096100b05
65b5b9291505056fea26469706673582212201920942fd6ffcf09c56617da5862
83bff44d1d3907bbd711959cae8b1b26947164736f6c634300081a0033
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Bytecode is the raw machine-level code that the &lt;strong&gt;EVM (Ethereum Virtual Machine)&lt;/strong&gt; understands — the actual &lt;strong&gt;executable logic&lt;/strong&gt; of the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Remix to deploy and run transactions
&lt;/h2&gt;

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

&lt;p&gt;Change the ENVIRONMENT to "Injected Provider - MetaMask" . (Please install Metamask if you have not done &lt;a href="https://dev.to/rwu_security_researcher/onboard-ethereum-a-beginners-guide-to-metamask-testnets-and-your-first-wallet-4lif"&gt;so&lt;/a&gt;.) The default MetaMask network is "Ethereum Mainnet", i.e. real ETH. In order to switch the network, you can click on the down arrow on the top left corn, and pop up a dialog like this&lt;/p&gt;

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

&lt;p&gt;Scroll all the way down, and turn on "Show test networks", and add "Sepolia", &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0mvz3dxu7afogtjes1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0mvz3dxu7afogtjes1v.png" alt="Sepolia Testnet" width="537" height="903"&gt;&lt;/a&gt;&lt;br&gt;
You can see the account has a balance of 0.05 SepoliaETH, (Not ETH). &lt;strong&gt;As the cryptocurrency always lives in a blockchain, even the pro must double check to make sure the wallet software (in this case MetaMask) uses the right "network".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you can click on "Deploy" button in remix.ethereum.org.&lt;/p&gt;

&lt;p&gt;Your browser will pop up a MetaMask dialog asking you to confirm the transaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr844akeinvh5wn7si57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr844akeinvh5wn7si57.png" alt="Deploy a contract " width="522" height="925"&gt;&lt;/a&gt;. &lt;strong&gt;When you enters the crypto world, you must be careful about what you confirms. If you have any doubt, it's safer to click "Cancel" instead of "Confirm".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After your confirmation and a couple of minutes, the bytecode of the contract will be deployed to the Sepolia Testnet &lt;strong&gt;FOREVER&lt;/strong&gt;, available for anyone to view and interact with.&lt;/p&gt;

&lt;p&gt;You can view the transaction I approved at &lt;a href="https://sepolia.etherscan.io/tx/0xe654e53a0661218cfc11528702e74e4df660b26a9fbc60445706f5b47a945887" rel="noopener noreferrer"&gt;https://sepolia.etherscan.io/tx/0xe654e53a0661218cfc11528702e74e4df660b26a9fbc60445706f5b47a945887&lt;/a&gt;. The transaction created a contract &lt;a href="https://sepolia.etherscan.io/address/0xce66d154524a190c48d879038deea2a6cf04a315" rel="noopener noreferrer"&gt;https://sepolia.etherscan.io/address/0xce66d154524a190c48d879038deea2a6cf04a315&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Interact with the contract using Remix
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reload Remix&lt;/li&gt;
&lt;li&gt;Compile Counter.sol&lt;/li&gt;
&lt;li&gt;Deploy &amp;amp; Run Transactions

&lt;ul&gt;
&lt;li&gt;Use Injected Provider - MetaMask&lt;/li&gt;
&lt;li&gt;Paste the contract address on the right "At Address" button 0xce66d154524a190c48d879038deea2a6cf04a315&lt;/li&gt;
&lt;li&gt;Click "At Address" button&lt;/li&gt;
&lt;li&gt;Scroll all the way down, you can see two buttons: "count" and "increment"&lt;/li&gt;
&lt;li&gt;Click on "count", you get 0: uint256: 0, we know the live contract 0xce66d154524a190c48d879038deea2a6cf04a315 has a count 0 as its attribute. Because the count is "public", there will be no cost to access it.&lt;/li&gt;
&lt;li&gt;Click on "increment", this button is orange, so it triggers MetaMask confirmation dialog because this method call will change the "count" attribute of the contract live in the Sepolia Testnet, so you have to pay the cost to initiate the "state" change. After confirmation and a couple of minutes, the count will be changed to 1.&lt;/li&gt;
&lt;li&gt;Click on "count" again, you get 0: uint256: 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  🌐 Bonus: Interacting Directly via Chrome Console (Advanced)
&lt;/h2&gt;

&lt;p&gt;If you're curious about how smart contracts are called and modified behind the scenes — without using Remix or libraries like ethers.js — here's a glimpse into interacting directly with the Ethereum network using the browser console and MetaMask.&lt;/p&gt;

&lt;p&gt;(Feel free to skip this if you just want to stick with Remix for now!)&lt;/p&gt;
&lt;h3&gt;
  
  
  🔥 Steps to Call &lt;code&gt;count()&lt;/code&gt; (Read the Public Variable)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the Chrome DevTools Console (&lt;code&gt;F12&lt;/code&gt; or &lt;code&gt;Ctrl+Shift+I&lt;/code&gt;, then go to the Console tab) in the remix page.&lt;/li&gt;
&lt;li&gt;Make sure MetaMask is unlocked and connected to Sepolia.&lt;/li&gt;
&lt;li&gt;Connect to MetaMask from the console:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_requestAccounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xce66d154524a190c48d879038deea2a6cf04a315&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;internalType&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uint256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uint256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stateMutability&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stateMutability&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nonpayable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Encode the ABI for the `count()` function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count()&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Alternatively, hardcode the function signature hash:&lt;/span&gt;
&lt;span class="c1"&gt;// keccak256("count()") first 4 bytes &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countDataEncoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x06661abd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;countDataEncoded&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eth_call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Decode result (hex string to number)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Current count is:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ You will see the current count (e.g., 1) printed directly into your console!&lt;/p&gt;
&lt;h3&gt;
  
  
  🔥 Send a Transaction to &lt;code&gt;increment()&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// `increment()` function signature: &lt;/span&gt;
&lt;span class="c1"&gt;// keccak256("increment()") first 4 bytes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incrementDataEncoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xd09de08a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transactionParameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_accounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}))[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;incrementDataEncoded&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eth_sendTransaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transactionParameters&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transaction sent. Hash:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ MetaMask will pop up asking you to approve and pay gas. After confirming, your count will increment.&lt;/p&gt;

&lt;p&gt;✅ After mining, you can call count() again to verify it changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eth_call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Decode result (hex string to number)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Current count is:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM274:7 Current count is: 2&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;EIP-1193: Ethereum Provider JavaScript API: &lt;a href="https://eips.ethereum.org/EIPS/eip-1193" rel="noopener noreferrer"&gt;https://eips.ethereum.org/EIPS/eip-1193&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pi7.org/hash/keccak-256" rel="noopener noreferrer"&gt;https://pi7.org/hash/keccak-256&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>metamask</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Onboard Ethereum: A Beginner’s Guide to MetaMask, Testnets, and Your First Wallet</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Thu, 24 Apr 2025 14:34:08 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/onboard-ethereum-a-beginners-guide-to-metamask-testnets-and-your-first-wallet-4lif</link>
      <guid>https://dev.to/rwu_security_researcher/onboard-ethereum-a-beginners-guide-to-metamask-testnets-and-your-first-wallet-4lif</guid>
      <description>&lt;p&gt;If you're curious about Ethereum but not sure where to start, this guide is for you. We'll help you set up your first wallet using MetaMask, connect to a test network, and try Ethereum safely — without spending real money.&lt;/p&gt;

&lt;p&gt;🦊 What is MetaMask?&lt;/p&gt;

&lt;p&gt;MetaMask is a crypto wallet and browser extension that lets you interact with the Ethereum blockchain — including sending transactions and using decentralized applications (dApps).&lt;/p&gt;

&lt;h2&gt;
  
  
  Install MetaMask and Set Up Your Wallet
&lt;/h2&gt;

&lt;p&gt;Visit &lt;a href="https://metamask.io" rel="noopener noreferrer"&gt;https://metamask.io&lt;/a&gt; and install the extension.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;For the 1st time user, click “Create a Wallet”&lt;/li&gt;
&lt;li&gt;If you're returning, click “Import an existing wallet”&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;p&gt;🔐 What Does the MetaMask Password Actually Do?&lt;/p&gt;

&lt;p&gt;This password can be a confusing concept for the first time user, so it’s important to understand what this password is (and isn’t).&lt;/p&gt;

&lt;p&gt;✅ What the MetaMask Password Does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It unlocks MetaMask locally on your browser or device.&lt;/li&gt;
&lt;li&gt;It encrypts your wallet data stored in the browser.&lt;/li&gt;
&lt;li&gt;It prevents casual access — someone using your computer can't open MetaMask without it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ What It Does Not Do&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not protect your wallet on the Ethereum network.&lt;/li&gt;
&lt;li&gt;It does not let you access your wallet from another browser or device.&lt;/li&gt;
&lt;li&gt;It does not act as a recovery method — resetting MetaMask will wipe this password along with your wallet data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 In Short&lt;/p&gt;

&lt;p&gt;The MetaMask password is like a lock screen for your wallet on one device. It's useful, but not portable, and not a backup.&lt;/p&gt;

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

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

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

&lt;p&gt;🔑 Understanding the Secret Recovery Phrase&lt;/p&gt;

&lt;p&gt;This 12-word Secret Recovery Phrase (also called a seed phrase) is the &lt;strong&gt;ONLY&lt;/strong&gt; way to restore your wallet if your browser is reset, your computer crashes, or you need to access it from a different device.&lt;/p&gt;

&lt;p&gt;✅ What It Is&lt;/p&gt;

&lt;p&gt;A randomly generated 12-word phrase that represents the private keys to your wallet.&lt;br&gt;
It’s used to recover all assets, tokens, and accounts tied to your MetaMask wallet.&lt;br&gt;
It’s standard across wallets — you can use it with other Ethereum-compatible wallets too.&lt;/p&gt;

&lt;p&gt;❌ What It’s Not&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s not a password you can reset.&lt;/li&gt;
&lt;li&gt;It’s not recoverable by MetaMask, you, or anyone else if lost.&lt;/li&gt;
&lt;li&gt;It’s not meant to be stored online or in screenshots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔐 How to Protect It&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write it down on paper — not in your Notes app, Google Docs, or email.&lt;/li&gt;
&lt;li&gt;Store it offline, ideally in multiple physical copies (like a notebook or safe).&lt;/li&gt;
&lt;li&gt;Never share it — if someone else gets your phrase, they can access all your funds instantly.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Your Secret Recovery Phrase as the master key to your wallet. Keep it safe, keep it secret, and never lose it.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Your Secret Recovery Phrase as the master key to your wallet. Keep it safe, keep it secret, and never lose it.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Your Secret Recovery Phrase as the master key to your wallet. Keep it safe, keep it secret, and never lose it.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;📬 Overview of Your New Ethereum Account&lt;/p&gt;

&lt;p&gt;Now you have your Ethereum account — in my case, it’s 0x31F6957daeB68d6B2809Af1c40a910E88Ce1D038.&lt;/p&gt;

&lt;p&gt;But where does this account actually live?&lt;/p&gt;

&lt;p&gt;It doesn’t exist in a bank, and it’s not stored in your browser either. Your account lives on the Ethereum network — or a compatible Ethereum-compatible blockchain — maintained by a global, decentralized, peer-to-peer network.&lt;/p&gt;

&lt;p&gt;To participate in that network, even on testnets, you’ll need some cryptocurrency to get started. That’s where faucets come in.&lt;/p&gt;

&lt;p&gt;💸 Get Free Test ETH (Faucets)&lt;/p&gt;

&lt;p&gt;To interact with the Ethereum test network, you’ll need some test ETH — fake ETH that only works on testnets like Sepolia. You can get it for free from a faucet.&lt;/p&gt;

&lt;p&gt;🪙 What’s a Faucet?&lt;/p&gt;

&lt;p&gt;A faucet is a website that gives you a small amount of test ETH so you can try things out — like sending transactions, paying gas, or deploying smart contracts&lt;/p&gt;

&lt;p&gt;🚰 How to Use a Faucet (Sepolia)&lt;/p&gt;

&lt;p&gt;Visit: &lt;a href="https://cloud.google.com/application/web3/faucet/ethereum/sepolia" rel="noopener noreferrer"&gt;Google Cloud Sepolia Faucet&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Paste your wallet address — for example:&lt;br&gt;
0x31F6957daeB68d6B2809Af1c40a910E88Ce1D038&lt;/p&gt;

&lt;p&gt;Click the “Receive 0.05 Sepolia ETH” button.&lt;/p&gt;

&lt;p&gt;Wait a minute or two for the test ETH to arrive.&lt;/p&gt;

&lt;p&gt;✅ Check the balance of the account at &lt;a href="https://sepolia.etherscan.io/address/0x31f6957daeb68d6b2809af1c40a910e88ce1d038" rel="noopener noreferrer"&gt;https://sepolia.etherscan.io/address/0x31f6957daeb68d6b2809af1c40a910e88ce1d038&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>beginners</category>
      <category>ethereum</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Understanding Walkthrough.sol Solidity Contract Explained in Detail</title>
      <dc:creator>Yuanyan Wu</dc:creator>
      <pubDate>Thu, 24 Apr 2025 02:12:25 +0000</pubDate>
      <link>https://dev.to/rwu_security_researcher/understanding-walkthroughsol-solidity-contract-explained-in-detail-5ccn</link>
      <guid>https://dev.to/rwu_security_researcher/understanding-walkthroughsol-solidity-contract-explained-in-detail-5ccn</guid>
      <description>&lt;p&gt;In this post, we'll treat Walkthrough.sol introduced in &lt;a href="https://dev.to/rwu_security_researcher/demystifying-solidity-a-step-by-step-guide-using-walkthroughsol-2in6"&gt;my previous post&lt;/a&gt; as a learning tool to explore fundamental Solidity syntax — including variable declarations, access control, string hashing, and constructor logic.&lt;/p&gt;

&lt;p&gt;/* Solidity can use /&lt;em&gt;...&lt;/em&gt;/ as the delimited comments */&lt;br&gt;
// as the line comments&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
/* SPDX-License-Identifier tells tools which license applies.
It's required for verified contracts but is not enforced by the 
compiler itself. */

pragma solidity ^0.8.0;
/* The pragma directive specifies the compiler version required
to compile the contract. This helps avoid issues caused by
breaking changes in future Solidity versions. */

/* This contract's name is "Walkthrough". It does not need to be
in Walkthrough.sol, but anyName.sol. */
contract Walkthrough {
    /* 'string public password' creates a publicly readable
string variable. The 'public' keyword automatically generates a
getter function. All state variables are stored permanently on
the blockchain once the contract is deployed. */
    string public password;
    /* 'uint8' is an unsigned 8-bit integer, ranging from 0 to 
255. */
    uint8 public infoNum = 42;
    string public theMethodName = "The method name is method7123949.";
    /* 'bool' is either true or false.*/
    /* 'private' restricts access to within the contract, but the 
value is still publicly viewable on the blockchain. */
    bool private cleared = false;

    // constructor
    /* The constructor runs once at deployment. The 'memory'
keyword indicates the string parameter is stored temporarily
during execution. */
    constructor(string memory _password) {
        password = _password;
    }

    /* 'pure' This function neither reads nor modifies state. It 
returns a static string. */
    function info() public pure returns (string memory) {
        return "You will find what you need in info1().";
    }

    function info1() public pure returns (string memory) {
        return 'Try info2(), but with "hello" as a parameter.';
    }

    function info2(string memory param) public pure returns (string memory) {
        /* keccak256 is a built-in cryptographic hash function in 
Solidity returns a fixed 32-byte (bytes32) hash. Solidity doesn’t 
support string comparisons like Java or Python. So developers use
keccak256 to compare strings safely.*/
        /* The built in solidity function abi.encodePacked(...) 
flattens the string into bytes just like string.toByteArray() in 
Java. */
        if (
            keccak256(abi.encodePacked(param)) ==
            keccak256(abi.encodePacked("hello"))
        ) {
            return
                "The property infoNum holds the number of the next info method to call.";
        }
        return "Wrong parameter.";
    }

    function info42() public pure returns (string memory) {
        return "theMethodName is the name of the next method.";
    }

    function method7123949() public pure returns (string memory) {
        return "If you know the password, submit it to authenticate().";
    }

    function authenticate(string memory passkey) public {
        if (
            keccak256(abi.encodePacked(passkey)) ==
            keccak256(abi.encodePacked(password))
        ) {
            cleared = true;
        }
    }

    /* 'view' - This function reads state (cleared) but doesn't 
modify it. Use for on-chain reads. */
    function getCleared() public view returns (bool) {
        return cleared;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;--&lt;/p&gt;

&lt;h2&gt;
  
  
  🎁 Bonus: Understanding &lt;code&gt;keccak256&lt;/code&gt; in Solidity
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;Walkthrough.sol&lt;/code&gt;, the password is verified using this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (keccak256(abi.encodePacked(passkey)) == 
keccak256(abi.encodePacked(password))) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔐 What is keccak256?&lt;br&gt;
keccak256 is a built-in cryptographic hash function in Solidity. It accepts arbitrary input (usually bytes) and returns a 32-byte (bytes32) deterministic hash. It is irreversible and collision-resistant.&lt;/p&gt;

&lt;p&gt;This is Ethereum’s version of SHA-3, used extensively in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comparing strings (since == doesn’t work directly)&lt;/li&gt;
&lt;li&gt;Creating unique IDs&lt;/li&gt;
&lt;li&gt;Generating signatures&lt;/li&gt;
&lt;li&gt;Building Merkle trees and proofs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧠 Why is it used here?&lt;br&gt;
Solidity does not support direct string comparison using == like other languages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (passkey == password) // ❌ Not allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, both strings are converted to bytes and hashed and compared:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (keccak256(abi.encodePacked(passkey)) == 
keccak256(abi.encodePacked(password)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If two strings are identical, their hashes will also be identical&lt;/li&gt;
&lt;li&gt;Comparing fixed-size bytes32 values is gas-efficient and secure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Common Gotchas&lt;br&gt;
Do not use abi.encodePacked() with multiple dynamic types (like string, bytes, or uint[]), as it may cause hash collisions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keccak256(abi.encodePacked("abc")) ==
keccak256(abi.encodePacked("a", "bc"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be safe, use abi.encode() if you’re hashing more than one variable.&lt;/p&gt;




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

&lt;p&gt;By dissecting &lt;code&gt;Walkthrough.sol&lt;/code&gt;, we've explored fundamental Solidity concepts, including state variables, function modifiers, and secure string comparisons. Understanding these elements is crucial for developing robust smart contracts. &lt;/p&gt;

&lt;p&gt;Try experimenting with this contract in Remix or your local development environment to solidify your understanding of Solidity's fundamentals.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>solidity</category>
      <category>blockchain</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
