<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>0x00myke</title>
        <link>https://paragraph.com/@0x00myke</link>
        <description>Am a web3 developer and also a technical writer I also write non technical things about the web3 space. </description>
        <lastBuildDate>Fri, 07 Aug 2026 15:55:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Why Transactions Fails(and how to debug them)]]></title>
            <link>https://paragraph.com/@0x00myke/why-transactions-fails-and-how-to-debug-them</link>
            <guid>L8Dj8slB8nBEc5WPNw2e</guid>
            <pubDate>Thu, 30 Oct 2025 08:16:01 GMT</pubDate>
            <description><![CDATA[NB : pls use AI tools or code editors for the code snippets in this article to get the proper format of the code for better understanding Short version up front: when you see “TX failed” you don’t need to guess — follow a small, repeatable checklist: 1)fetch receipt → 2) decode revert → 3) check gas/nonce/balance → 4) reproduce locally (fork) → 5) trace and fix state/ABI/permission problems. Below is a plain, step-by-step article you can use to debug your transactions.TL;DR (one-minute checkl...]]></description>
            <content:encoded><![CDATA[<p><strong>NB : pls use AI tools or code editors for the code snippets in this article to get the proper format of the code for better understanding</strong></p><p>Short version up front: when you see “TX failed” you don’t need to guess — follow a small, repeatable checklist:</p><p>1)fetch receipt → 2) decode revert → 3) check gas/nonce/balance → 4) reproduce locally (fork) → 5) trace and fix state/ABI/permission problems.</p><p>Below is a plain, step-by-step article you can use to debug your transactions.</p><hr><p><strong>TL;DR (one-minute checklist)</strong></p><ul><li><p>Get the tx receipt (eth_getTransactionReceipt). Look at status, gasUsed, logs.</p></li><li><p>Try the same call with eth_call (or provider.call) to get a revert reason.</p></li><li><p>eth_estimateGas vs submitted gas → Out-of-gas?</p></li><li><p>Check eth_getTransactionByHash + txpool for nonce/pending issues.</p></li><li><p>Reproduce on a local fork (anvil/hardhat) and use debug_traceTransaction to find the failing opcode.</p></li></ul><p>Fix: allowance, approvals, owner/paused guards, correct ABI/address, or bump gas/nonce.</p><hr><p><strong>Who This is for &amp; quick setup</strong></p><p>Target: Solidity engineers, integrators, infra/devops, and anyone sending transactions from wallets or bots.</p><p>You need:</p><p>A JSON-RPC URL (Infura, Alchemy, QuickNode, or your running node).</p><p>Tools (pick any): curl + node’s RPC, Foundry cast/anvil, Hardhat, ethers.js.</p><p>Optional but useful: access to node with debug_traceTransaction enabled (geth or anvil do this).</p><p><strong>Quick setup commands (examples):</strong></p><ul><li><p>Start a forked anvil (Foundry)</p></li></ul><p>anvil --fork-url <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mainnet.infura.io/v3/$INFURA_KEY">https://mainnet.infura.io/v3/$INFURA_KEY</a> --fork-block-number 18400000</p><ul><li><p>or start Hardhat node fork</p></li></ul><p>npx hardhat node --fork <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mainnet.infura.io/v3/$INFURA_KEY">https://mainnet.infura.io/v3/$INFURA_KEY</a> --fork-block-number 18400000</p><hr><p><strong>Quick triage (first 60 seconds)</strong></p><p>Run these checks immediately to eliminate common mistakes:</p><ol><li><p>Are you on the right chain / network id?</p></li><li><p>Is the contract address correct and actually a contract? (eth_getCode)</p></li><li><p>Does the sender have enough ETH? (eth_getBalance)</p></li><li><p>Is your nonce correct / any pending tx? (eth_getTransactionByHash + txpool)</p></li><li><p>Is there a missing token approve / allowance?</p></li><li><p>Was the gas limit too low?</p></li></ol><p><strong>Commands to run right away:</strong></p><ul><li><p>Receipts</p></li></ul><p>curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getTransactionReceipt&quot;,&quot;params&quot;:[&quot;&quot;],&quot;id&quot;:1}&apos; $RPC_URL Balance curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getBalance&quot;,&quot;params&quot;:[&quot;&quot;, &quot;latest&quot;],&quot;id&quot;:1}&apos; $RPC_URL Check if address has code (is a contract) curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getCode&quot;,&quot;params&quot;:[&quot;</p><p>&quot;,&quot;latest&quot;],&quot;id&quot;:1}&apos; $RPC_URL</p><hr><p><strong>Step 0 — Capture the exact tx data (always do this)</strong></p><p>Before changing anything, copy the full original tx fields: from, to, data, value, gas, gasPrice or maxFeePerGas &amp; maxPriorityFeePerGas, and nonce. You’ll replay this exact set in a local fork.</p><p>You can fetch the on-chain transaction:</p><p>curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getTransactionByHash&quot;,&quot;params&quot;:[&quot;&quot;],&quot;id&quot;:1}&apos; $RPC_URL Store those fields — they are the canonical reproduction input. <strong>Step 1 — Inspect the receipt &amp; quick interpretation</strong> Look at the transaction receipt fields of interest: status — 0 means revert; 1 means success. gasUsed — compare with what you set in gas. If gasUsed ≈ gas limit, likely OOG. logs — if events you expected are missing, the code likely reverted before emitting them. blockNumber — helpful to choose a fork block close to the original. Example interpretation: status: 0, gasUsed: 21000 → revert early (require/owner check or immediate revert) status: 0, gasUsed ~= gasLimit → likely ran out of gas <strong>Step 2 — Decode the revert reason</strong> If the node returns revert data, decode it. Use eth_call (simulation) because many providers return the revert string when simulating a call. Ethers.js quick pattern: try { await provider.call({ to: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://tx.to">tx.to</a>, data: tx.data, from: tx.from, value: tx.value }); } catch (err) { console.error(&quot;revert data:&quot;, err.error || err.data || err); // If you have the ABI, use new ethers.utils.Interface(abi).parseError(revertData) } If the revert data is ABI-encoded custom error, decode it with the contract ABI: const iface = new ethers.utils.Interface(contractAbi); const parsed = iface.parseError(revertData); // works for custom errors If you only have raw bytes, first check for the standard Error selector (0x08c379a0 = &quot;Error(string)&quot;): 0x08c379a0 + encoded string → normal require(&quot;message&quot;). If another selector appears, it’s a custom error — parse with the ABI. If the RPC doesn’t return a revert string, use local fork + provider.call or debug_traceTransaction to see more. <strong>Step 3 — Gas and out-of-gas checks</strong> Compare submitted gas to eth_estimateGas. If eth_estimateGas &gt;&gt; submitted gas → raise gas limit. If gasUsed is very close to gas limit, increase it. Commands: Estimate gas for the same transaction curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_estimateGas&quot;,&quot;params&quot;:[{ &quot;to&quot;:&quot;&quot;,&quot;data&quot;:&quot;0x...&quot;,&quot;from&quot;:&quot;0x...&quot; }],&quot;id&quot;:1}&apos; $RPC_URL Notes: eth_estimateGas can fail if the call always reverts. Use a local fork and manipulate state to get a meaningful estimate if needed. On EIP-1559 chains, ensure maxFeePerGas and maxPriorityFeePerGas are set correctly. <strong>Step 4 — Nonce / pending / replacement issues</strong> Symptoms: tx stays pending, or you get replacement transaction underpriced. Quick checks: eth_getTransactionByHash — looks at tx status. txpool_content (node-dependent) — inspect pending transactions. Replace a stuck tx by resending with same nonce and a higher gas price / tip. Commands: txpool (Geth/Parity specific) curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;txpool_content&quot;,&quot;params&quot;:[],&quot;id&quot;:1}&apos; $RPC_URL If you control the key, common fix is to resend a new transaction with same nonce + higher fee. <strong>Step 5 — Reproduce the failure locally (forking)</strong> Forking is the single most powerful debugging step. Start a local node at a block near the tx and replay the exact tx. Anvil (Foundry) example: anvil --fork-url $RPC_URL --fork-block-number -p 8545 Then use ethers or cast to call the tx or send the exact transaction fields to see the same failure locally. On a fork you can also change balances, allowances, or contract storage to test state-dependent failures. Replaying call with cast: cast call &quot;methodName(type...)&quot; params --rpc-url <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://127.0.0.1:8545">http://127.0.0.1:8545</a> Replaying raw via ethers: await provider.call({ to, data, from, value, gasLimit: gas }); <strong>Step 6 — Trace the transaction to find the failing opcode</strong> Use debug_traceTransaction to get a call-tree and the point of revert. This helps identify whether a particular external call reverts, a require fails, or an out-of-gas occurs. Example RPC: curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;debug_traceTransaction&quot;,&quot;params&quot;:[&quot;&quot;, {&quot;tracer&quot;:&quot;callTracer&quot;}],&quot;id&quot;:1}&apos; $RPC_URL Interpreting traces: Look for the last call in the call tree with error or revert. The trace may show the failing internal call (for example CALL to token contract failed). If you run traces locally with anvil/hardhat you’ll often get richer data than public nodes. <strong>Step 7 — State-dependent issues (allowance, balances, timestamps)</strong> Many reverts depend on the exact on-chain state at execution time: Common checks: ERC20 allowance(owner, spender) and balanceOf(owner). Contract paused() status. Role/owner checks: owner() or hasRole(...). Block/time dependence: block.timestamp or block.number used in logic. On your fork you can mutate state before replaying: Transfer tokens into the account. Call a helper to set oracle price or mock contract responses. Increase allowance. Example cast calls: check allowance (foundry cast) cast call &quot;allowance(address,address)(uint256)&quot; $OWNER $SPENDER --rpc-url <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://127.0.0.1:8545">http://127.0.0.1:8545</a> <strong>Step 8 — External calls, oracles, and non-determinism</strong> If your function calls other contracts or oracles, those external calls can revert or return unexpected values (zero price, stale timestamp, etc). How to handle: Trace to find which external call failed. On a fork, patch oracle storage or deploy a mock and point the caller to it. For production fixes, add sanity checks (e.g., require(price &gt; 0) or fallback behaviors). <strong>Step 9 — Permission, pausability, initializer mistakes</strong> Typical access issues: Contract still paused. Function restricted to onlyOwner or role-based guard. Missing initialize() or setup steps after deployment (proxy patterns). Quick checks: const c = await ethers.getContractAt(&quot;MyContract&quot;, &quot;</p><p>&quot;); await c.owner(); await c.paused();</p><p>If you see revert: Ownable: caller is not the owner — adjust the caller or correct owner assignment.</p><hr><p><strong>Step 10 — ABI, address, and chain mismatch</strong></p><p>If you call the wrong address or wrong ABI, functions can revert or behave unexpectedly.</p><p>Checks:</p><ul><li><p>eth_getCode(address) should return non-empty hex for a contract.</p></li><li><p>Verified contract ABI from Etherscan / block explorer should match what you use locally.</p></li><li><p>For proxies, ensure you’re interacting with the proxy address with the implementation ABI (or use the proxy’s interface).</p></li></ul><p>Command:</p><p>curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &apos;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getCode&quot;,&quot;params&quot;:[&quot;&quot;,&quot;latest&quot;],&quot;id&quot;:1}&apos; $RPC_URL <strong>Tooling quick-reference :</strong> anvil (Foundry) — fast local fork and tracing. anvil --fork-url --fork-block-number hardhat — local fork + console: npx hardhat node --fork cast — quick read/write: cast call / cast send ethers.js — provider.call() to simulate, provider.getTransaction() to fetch txs debug_traceTransaction — use for opcode-level trace (requires node support) Tenderly / Blocknative / Etherscan TX viewer — nice UI for replays/traces <strong>Ready scripts: fetch + replay + decode (copy/paste)</strong> replay-tx.js (node + ethers) — simulate and show revert data // Usage: node replay-tx.js const { ethers } = require(&quot;ethers&quot;); (async () =&gt; { const [txHash, rpc] = process.argv.slice(2); if (!txHash || !rpc) { console.error(&quot;Usage: node replay-tx.js &quot;); process.exit(1); } const provider = new ethers.providers.JsonRpcProvider(rpc); const tx = await provider.getTransaction(txHash); console.log(&quot;tx:&quot;, tx); try { const res = await provider.call({ to: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://tx.to">tx.to</a>, data: tx.data, from: tx.from, value: tx.value, gasLimit: tx.gasLimit }); console.log(&quot;call success (returned data):&quot;, res); } catch (e) { console.error(&quot;call reverted. raw:&quot;, e.error || e.data || e); } })(); <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://quick-receipt.sh">quick-receipt.sh</a> #!/usr/bin/env bash RPC=$1 TX=$2 curl -s -X POST -H &quot;Content-Type:application/json&quot; --data &quot;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;eth_getTransactionReceipt&quot;,&quot;params&quot;:[&quot;$TX&quot;],&quot;id&quot;:1}&quot; $RPC | jq . <strong>Short case studies :</strong> Case A — Missing ERC20 allowance Symptom: call to a marketplace contract reverts. Receipt shows status:0, no logs. Debug steps: Check allowance(owner,market) → returns 0. Approve correct amount and re-run the tx. Fix: erc20.approve(market, amount) or use permit() flow if available. Case B — Oracle returns 0 (price = 0) Symptom: Action reverts because division by zero or require(price &gt; 0). Debug steps: Trace shows external call to PriceFeed.latestAnswer() returned 0. On a local fork set the oracle storage to a non-zero price or deploy a mock oracle. Fix: Update oracle, add guards to your contract, and add alerting on price feed changes. Case C — Out-of-gas because client used too small gasLimit Symptom: gasUsed equals the submitted gas and tx reverted. Debug steps: eth_estimateGas returns higher value. Resend with increased gas limit or allow miner to pick gas. Fix: Use estimation in client or set a safe multiplier (e.g., 1.3 * estimateGas). <strong>Advanced gotchas (short list)</strong> Reentrancy / ordering: race conditions cause different behavior under MEV/front-running. Constructor/initializer mismatch in proxies: calling implementation methods before initialization. Non-standard ERC20s: tokens that don’t return bool on transfer — use wrappers like OpenZeppelin SafeERC20. State shadowing / wrong storage slot: particularly when using low-level assembly or incorrect inheritance. Chain reorganizations: rare, but can cause txs to reappear or reorder relative to observed state. <strong>One-page troubleshooting flow (copyable)</strong> Get receipt (eth_getTransactionReceipt). If status == 1, the tx succeeded — check downstream logic. If status == 0 -&gt; run provider.call()/eth_call with same fields to capture revert reason. eth_estimateGas vs gas limit → OOG? Increase gas if estimate &gt; gas. Check eth_getBalance(from), allowance, and owner/paused flags. Fork locally (anvil/hardhat) at a nearby block and replay transaction. Mutate state if needed and rerun. Use debug_traceTransaction to see which internal call/opcode failed. Fix source (approve, set owner, update oracle, correct ABI/address, bump gas) and re-test on fork before sending live. <strong>Summary</strong> When you see “TX failed”, don’t panic. Capture the tx fields, fetch the receipt, simulate the call to get the revert reason, reproduce on a local fork, and use traces to find the failing unit. Most failures are one of: permission, missing approval, out-of-gas, wrong ABI/address, or state-dependent external data. <strong>How helpful was this article ?</strong> <strong>Tip: some codes snippets in this article may not appear properly formatted. To veiw them clearly you can copy and Paste each snippoet into an AI tool or code editor to automatically format and highlight the structure for better readability.</strong> Follow me on X : @mykereckon Connect with me on Zora : <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zora.co/invite/myke_027">https://zora.co/invite/myke_027</a></p>]]></content:encoded>
            <author>0x00myke@newsletter.paragraph.com (0x00myke)</author>
        </item>
    </channel>
</rss>