DEV Community

Low Key Builds
Low Key Builds

Posted on

I decoded every failed transaction in 40 Ethereum blocks and 150 Base blocks. Here is why they fail.

"Transaction failed" on a block explorer tells you almost nothing. "Fail with error 'execution reverted'" tells you less. So I took every failed transaction from a recent run of blocks on Ethereum mainnet and on Base, replayed each one against the state of the previous block, decoded the revert data, and counted.

Disclosure: I built the decoder used here, Pitcrew. Its free web version is linked at the end. The sampling script and raw results are linked below, so you can rerun the numbers.

The sample

Ethereum Base
Blocks 26,182,107 to 26,182,146 (40) 52,543,866 to 52,544,015 (150)
Transactions 11,080 30,809
Failed 401 (3.6%) 2,745 (8.9%)

Method: for each failed receipt, fetch the transaction, eth_call it with the same from/to/data/value/gas against the parent block, then decode the revert data: Error(string), Panic(uint256), or a custom error selector looked up in the openchain signature database. Free public RPCs only.

Ethereum: why the 401 failed

Share Count Cause
50.1% 201 21,000-gas ETH send to an EIP-7702 account (all 0.0000001 ETH dust)
27.4% 110 state changed earlier in the same block (lost a race: MEV/arb/front-run)
8.7% 35 reverted with no reason
6.5% 26 slippage / price moved
2.5% 10 out of gas (gas limit too low)
2.0% 8 balance or allowance too low
1.7% 7 other require() message
1.0% 4 custom error (needs ABI/signature lookup)

Half of all failures were one pattern: 21,000 gas sent to EIP-7702 accounts

201 of the 401 failures were plain ETH sends (no calldata) with a gas limit of exactly 21,000, and every one used all of it. All 50 recipients had EIP-7702 delegation code (0xef0100...), pointing at, among others, MetaMask's delegator and Uniswap's Calibur account.

Since Pectra, an EOA can delegate to contract code. When you send it ETH, that code runs, so 21,000 gas is no longer enough. Anything that hard-codes 21,000 for "simple ETH transfers" (scripts, payout bots, older wallet code) will fail against these accounts every time, and retrying with the same limit changes nothing.

To be honest about this sample: every one of these 201 sends was 0.0000001 ETH from 52 addresses retrying 5 to 8 times in eight minutes. That looks like automated dusting, not people losing money. The failure mode is still real for any payout code that sends ETH with a fixed 21,000 gas. Fix: estimate gas for ETH sends, or detect 0xef0100 code on the recipient and raise the limit.

A quarter could not be reproduced: you lost a race

110 failures (27%) succeeded when replayed against the previous block's state. They failed because a transaction earlier in the same block changed something: a price, a reserve, a nonce. These are mostly arbitrage and MEV bots losing races, but if you see this on your own swap, someone else's transaction landed first.

The ones that hurt people: slippage, balance and allowance

  • Slippage guards (INSUFFICIENT_OUTPUT_AMOUNT, Too little received, Min return not reached): 26
  • ERC20: transfer amount exceeds balance, STF (Uniswap's "safeTransferFrom failed", usually a missing approval or balance): 8
  • Out of gas with a real call: 10

STF deserves a special mention because nobody knows what it means. It is Uniswap V3's TransferHelper saying transferFrom failed: the router could not pull your tokens. Check the allowance first, then the balance (and fee-on-transfer tokens).

Base: why the 2,745 failed

Share Count Cause
58.9% 1616 state changed earlier in the same block (lost a race: MEV/arb/front-run)
15.0% 413 custom error (needs ABI/signature lookup)
14.4% 394 other require() message
8.1% 221 reverted with no reason
2.8% 76 slippage / price moved
0.5% 15 balance or allowance too low
0.4% 10 out of gas (gas limit too low)

Base fails 2.5 times as often as Ethereum, and its failures are mostly bots. 59% are lost races: they succeed when replayed a block earlier, and 800 distinct senders produced 2,745 failures, with the top sender (0xc0ffeebabe...) alone accounting for 98. Gas on Base is cheap enough that bots fire speculative transactions and accept that most will fail.

The revert strings show it: the top messages after "no reason" are sl, SPL, SPL1, sbl1, :( and LEG_1_FAILED. Those are private bot contracts saving bytes, not anything a user would see.

Human-facing failures are a small share on Base: slippage guards (Min return not reached, TooMuchSlippage, QuoteBelowMin, OutputTooLow) 2.8%, balance and allowance (transferFrom reverted, STF) 0.5%. 15% end in a custom error, and many of those selectors are not in any public signature database, so an explorer shows only hex. If you are a person debugging your own failed Base transaction, the most likely causes are still slippage and allowance. Just don't expect the network-wide numbers to look like your experience.

Reproduce it

The script is about 80 lines of Node with no API keys: failed_txs.mjs. It runs eth_getBlockReceipts per block, then replays each failure at block - 1.

Decode your own

If you have a failed or stuck transaction, paste the hash into the free checker: https://pitcrew-api.appin60.com/app (Ethereum, Base, Arbitrum, Optimism, Polygon, BSC; 20 free checks a day). It returns the decoded revert reason, gas used vs limit, token transfers and a plain-language fix. Stuck transactions get the nonce-gap and replace/cancel recipe. If your agent needs it, the same call is pay-per-use over x402 at $0.01 (GET /tx/explain?chain=base&hash=0x..., USDC on Base or Arbitrum).

Caveat: replaying against the parent block is an approximation. When an earlier transaction in the same block changed the state, the replay succeeds and the tool says so instead of guessing.

Top comments (0)