Skip to content

The Pre-1559 First-Price Auction

In Gas Limit, Gas Used, and the Fee Formula we settled how much gas a transaction consumes: the EVM meters every opcode, and gas_used is the sum of what it executes. That answers the quantity question. It says nothing about the price question — how many wei you pay per unit of gas. This page is about how Ethereum answered that question for its first six years, from launch in 2015 until the London upgrade of August 2021.

The answer was blunt and, in hindsight, painful: a blind first-price auction. Each transaction carried one number, gasPrice, and that number was your bid. Miners sorted the pending transactions by that bid and packed the block with the highest ones. There was no protocol-computed price, no signal of what the “right” bid was — just you, guessing, against everyone else guessing. Understanding exactly why that hurt is the whole motivation for EIP-1559, which the next page builds. So we study the old mechanism carefully first: you cannot appreciate a fix until you feel the bug.

The mechanism: one number, sorted greedily

Section titled “The mechanism: one number, sorted greedily”

A legacy transaction (the nine-field RLP list from Transaction Types) carried a single fee field, gasPrice, denominated in wei per gas (usually quoted in gwei, where 1 gwei = 10⁹ wei = 10⁻⁹ ETH). The total fee was the same product we derived last page:

fee_paid = gas_used × gasPrice

There was no split, no burn, no target. Whatever you set as gasPrice, you paid — in full — and the entire amount went to the miner who included your transaction. That last fact matters: the miner’s income was exactly the sum of gas_used × gasPrice over every transaction in the block, so miners had a direct, mechanical incentive to include the highest-bidding transactions they could fit.

A miner (pre-Merge, Ethereum used proof-of-work) held a mempool of pending transactions — the local pool we described in The Mempool and Propagation. Building a block was a greedy knapsack:

MEMPOOL (each tx: gasPrice bid, gasLimit)
┌───────────────────────────────────────────┐
│ tx A 200 gwei 21,000 gas │
│ tx B 150 gwei 90,000 gas │
│ tx C 140 gwei 21,000 gas │
│ tx D 45 gwei 21,000 gas │
│ tx E 12 gwei 120,000 gas │
└───────────────────────────────────────────┘
│ 1. sort by gasPrice, high → low
┌───────────────────────────────────────────┐
│ A(200) · B(150) · C(140) · D(45) · E(12) │
└───────────────────────────────────────────┘
│ 2. pour into the block until the
│ ~12,500,000 gas ceiling is hit
┌─────────────── BLOCK ──────────────────────┐
│ A + B + C + D … (E left behind, too low) │
│ running gas total ≤ block gas limit │
└─────────────────────────────────────────────┘

Two properties fall straight out of this and define the whole experience:

  1. The block has a fixed size. Pre-London the block gas limit was a single hard ceiling (around 12.5M gas for much of that era, later 15M). It was not elastic — there was no notion of “target” versus “max” yet. When demand exceeded that ceiling, transactions competed for a genuinely scarce, fixed number of slots.
  2. Inclusion is decided by a threshold you cannot see. There is some clearing price — the gasPrice of the lowest bid that still made it into the block. Bid above it and you are in; bid below it and you wait. But that threshold only exists after the block is built. When you sign your transaction, it has not happened yet.

That second property is the entire problem. Let’s name it.

The first-price-auction problem: bidding blind

Section titled “The first-price-auction problem: bidding blind”

This is a sealed-bid, first-price auction: every bidder submits one number, the highest bidders win the fixed supply of slots, and each winner pays exactly what they bid — not the clearing price, but their own number. Economists have studied this format for decades, and it has a well-known pathology, which Ethereum inherited wholesale.

In a first-price auction, your optimal bid is not your true value. It is your best guess of the clearing price plus a small margin. If everyone must guess the clearing price, two bad outcomes are unavoidable:

  • Overpay, or
  • Underbid and get stuck.

There is no third option that is simultaneously cheap and reliable, because you are committing to a price before you can observe the price. Concretely:

You value getting in this block at "worth it up to 300 gwei."
The true clearing price will turn out to be 140 gwei.
You bid 300 → you get in, but you pay 300 and 140 would have sufficed.
You overpaid by 160 gwei × gas_used. (money left on the table)
You bid 130 → you are one gwei short. You are NOT in this block.
You wait — maybe minutes, maybe the tx is dropped entirely.

Because you pay your own bid, the safe strategy under uncertainty is to bid high — well above what you think you’ll need — so you don’t get stranded. And when many users all reason that way, they all overpay together. The auction systematically transfers more money to miners than a well-designed mechanism would need, and it does so most severely for the users who can least afford to babysit a stuck transaction.

Why fees were volatile and impossible to estimate

Section titled “Why fees were volatile and impossible to estimate”

The overpayment problem is bad on a calm day. On a busy day it compounds into wild volatility, for a structural reason: the protocol published no price signal at all.

Under this design there is nothing in the block header, nothing in the state, that says “gas currently costs X.” The only evidence of the market price is indirect and lagging — you can look at the gasPrices in the last few blocks and guess the next one. So every wallet had to build a fee oracle: a heuristic that scrapes recent blocks and the mempool and spits out a suggested gasPrice. Common approaches were crude by necessity:

  • Take the Nth percentile of gasPrices in the last k blocks (e.g. the 60th percentile of the last 20 blocks).
  • Offer users “slow / average / fast” tiers, each a different percentile, letting the user gamble on latency versus cost.
  • Watch the mempool depth and bump the estimate when the backlog grew.

These heuristics share a fatal weakness: they describe the recent past, and demand can jump faster than the past can predict. When a hyped NFT mint or a token launch opened, thousands of users flooded the mempool in the same few seconds, all bidding aggressively to land in the same block. The clearing price could quadruple between one block and the next, leaving every oracle’s estimate stale and every “average” transaction stuck.

gasPrice a wallet would suggest, over ~a few minutes of a mint:
gwei
1200 | ╷
1000 | ╱ ╲
800 | ╱ ╲
600 | ╱ ╲___
400 | ___ ╱ ╲___
200 |___ ╱ ╲___╱ ╲___
20 | ╲___╱
└────────────────────────────────────────────► time
calm a mint opens; everyone bids up at once decay

The feedback loop was vicious. High, uncertain prices pushed wallets to pad their suggestions to avoid stuck transactions; padded suggestions raised the realized clearing price; the higher clearing price justified even higher suggestions. There was no anchor — no protocol-set number the whole network could agree was “the price right now” — so the market discovered price by everyone shouting numbers at once and hoping.

Under the hood — stuck transactions and the nonce trap

Section titled “Under the hood — stuck transactions and the nonce trap”

The pain was worse than “wait a bit longer,” because of the nonce. An account’s transactions must execute in strict nonce order: nonce 5 cannot confirm before nonce 4. If you underbid on nonce 4, it sits in the mempool — and every later transaction you send is blocked behind it, no matter how high they bid. Your whole account is wedged.

The only escapes were both awkward:

  • Replace-by-fee (RBF): re-broadcast the same nonce with a higher gasPrice, asking miners to prefer the new version. This worked but required a wallet that understood it, and you often had to overpay again to be sure.
  • Cancel: send a 0-ETH transaction to yourself at the same nonce with a high enough bid to clear, burning gas purely to un-wedge the queue.

So the blind auction didn’t just cost money — it created a class of confusing, scary states (“my transaction is stuck and my other ones won’t send”) that ordinary users had no framework to understand. This is a big part of why the redesign was worth a hard fork: the mechanism was hostile to humans, not merely inefficient.

The same family as Bitcoin’s sat/vB auction

Section titled “The same family as Bitcoin’s sat/vB auction”

If this feels familiar from the Bitcoin book, it should. Bitcoin’s fee market is the same open first-price auction — a fixed-size block, users bidding a rate, miners sorting by rate and filling greedily, the winner paying their own bid. The mechanism is identical; only the unit being metered differs:

Bitcoin (pre-/post, unchanged) Ethereum (pre-London, 2015–2021)
meters in virtual bytes (vB) gas units
you bid sat / vB wei / gas (gwei)
miner sorts by fee rate, high → low gasPrice, high → low
block ceiling ~4,000,000 weight units ~12.5M–15M gas (fixed)
winner pays own bid own bid
fee goes to miner miner

This is the key generalization: “open first-price auction over a fixed-size block” is a whole family of fee mechanisms, and the two biggest chains both started there. Bitcoin meters data because a Bitcoin transaction is essentially bytes to store; Ethereum meters computation because an Ethereum transaction runs code (recall our companion crate’s mini-EVM, where every opcode has a gas_cost — a PUSH costs 3, an SSTORE costs 200). But the auction wrapped around that metering was the same design. Bitcoin, as of 2024, still uses this pure auction. Ethereum decided the human cost was too high and changed it. That divergence is the story of the next page.

The pre-1559 auction is a major mechanism — the first thing Ethereum used to price its scarce resource — so it earns the five questions, even though it was ultimately replaced.

  • Why does it exist? Because blockspace is a bounded, scarce resource and some mechanism must ration it. An open auction is the most obvious one: let users bid, let the block-producer take the highest bids. It requires zero protocol machinery to compute a price — the market discovers it.
  • What problem does it solve? Allocation and spam resistance. A fixed-size block can’t hold everyone, so the auction decides who gets in (the highest bidders) and makes flooding the chain expensive, keeping the shared ledger cheap to verify.
  • What are the trade-offs? It forces every user to guess the clearing price blind and pay their own bid, which drives systematic overpayment or stuck transactions. It publishes no price signal, so wallets resort to lagging heuristics that swing violently under congestion. Simple to implement, hostile to use.
  • When should I avoid it? When user experience and predictable fees matter more than mechanism simplicity — exactly Ethereum’s situation as it scaled to millions of non-expert users. (Where the auction is between sophisticated, latency-tolerant actors, or the chain values minimalism above all, it can be fine — Bitcoin still runs it.)
  • What breaks if I remove it? If you remove pricing entirely, the fixed block has no rationing rule and no spam filter — the ledger becomes floodable. So you don’t remove the auction; you replace it with something that keeps the rationing but kills the blind-bidding pain. That replacement is EIP-1559.

How do untrusting strangers agree on the state of a shared world computer — and what does it cost to run one? The auction is where “what does it cost” first meets “strangers who don’t trust each other.” No central authority sets the price of computation on Ethereum; the price is whatever a decentralized crowd of bidders and profit-seeking miners settle on, block by block. The pre-1559 design proved that a permissionless price can be discovered with almost no protocol machinery — a genuine achievement — but it also proved that “the market will sort it out” leaves ordinary users overpaying and confused. The next page shows how EIP-1559 keeps the decentralization while replacing the blind guess with a protocol-computed base fee — and, in a twist, burns it rather than paying it to the block-producer.

Onward to EIP-1559: Base Fee, Priority Fee, and the Burn.

  1. In the pre-1559 mechanism, what single field did a transaction use to bid, what did the total fee equal, and who received the whole fee?
  2. Why is a first-price auction said to cause “systematic overpayment”? Walk through the reasoning that makes a high bid the safe strategy.
  3. The protocol published no price signal before London. Explain how wallets estimated gasPrice anyway, and why those estimates broke down during a sudden surge like an NFT mint.
  4. How does the account nonce turn a single underpriced transaction into a stuck account, and what were the two ways out?
  5. Bitcoin’s sat/vB market and pre-London Ethereum are “the same auction family.” State precisely what is identical and what differs between them.
Show answers
  1. The transaction set a single gasPrice (in wei/gwei per gas). The total fee was gas_used × gasPrice, and the entire amount went to the miner who included the transaction — there was no split and no burn.
  2. Because it is a sealed-bid, first-price auction, you must commit to a bid before the clearing price is known, and you pay your own bid if you win. Bidding too low risks getting stranded (no confirmation, indefinite wait); bidding high guarantees inclusion. Under uncertainty the loss-averse move is to bid well above the expected clearing price — and when everyone does that, everyone overpays together, transferring excess value to miners.
  3. Wallets ran fee oracles: heuristics that scraped recent blocks (e.g. the Nth percentile of gasPrices over the last k blocks) and mempool depth to suggest a bid, often as “slow/average/fast” tiers. These describe the recent past, so when demand spiked in seconds — an NFT mint, a token launch — the clearing price could multiply between blocks, leaving the estimate stale and “average” transactions stuck.
  4. An account’s transactions must confirm in strict nonce order, so if nonce n is underpriced and waiting, every later transaction (nonce n+1, n+2, …) is blocked behind it regardless of its own bid — the whole account is wedged. The two escapes were replace-by-fee (re-broadcast the same nonce with a higher gasPrice) or cancel (a same-nonce, high-bid transaction to yourself that clears the queue).
  5. Identical: an open first-price auction over a fixed-size block — users bid a rate, the miner sorts by rate high-to-low and fills greedily, the winner pays their own bid, and the fee goes to the miner. Different: the unit metered — Bitcoin meters data in virtual bytes and you bid sat/vB; Ethereum meters computation in gas and you bid wei/gas (gwei). The auction wrapper is the same; the thing being auctioned differs.