Skip to content
Ethras
Menu
← All articles

Ethras Blog

Estimate Ethereum Fees with eth_feeHistory Without Promising Inclusion

Read base-fee history and tip percentiles, keep fee caps separate from gas limits, and design an estimator with explicit freshness and spending policies.

By Ethras Team ·

A fee estimator has two jobs: describe the market it observed and explain the spending policy it chose. Returning one number without either context makes it difficult to debug a stuck transaction or explain a surprisingly expensive one.

For an ordinary Ethereum type-2 transaction, eth_feeHistory is a useful input. It supplies recent block observations that your application can combine with its own urgency and budget rules. It does not decide those rules for you.

Start with a small, explicit query

This is a valid JSON-RPC request body, shown for reading rather than as a live probe:

{
  "jsonrpc": "2.0",
  "id": "fees-1",
  "method": "eth_feeHistory",
  "params": ["0x4", "latest", [25, 50, 75]]
}

It requests four blocks ending at latest, with three tip percentiles. According to the execution API definition, the returned range may be shorter than requested. oldestBlock identifies its start. The baseFeePerGas array includes one additional value for the block after the returned range. Each reward row reports effective priority-fee percentiles weighted by gas consumed. gasUsedRatio is gas used divided by block gas limit.

Our recommendation is to derive the actual sample count from the response and validate the array lengths before using it. With n = gasUsedRatio.length, expect n + 1 base-fee entries; baseFeePerGas[n] describes the block after the sample. In this query, reward[i][1] is the middle requested percentile for sample block i. Do not assume a four-block request produced four useful observations. Reject malformed data and surface insufficient history as an estimator condition.

Store the sample's block range and observation time. That gives support staff something concrete to inspect when a user asks why a particular fee was suggested.

Keep four quantities separate

For a type-2 transaction, let B be the inclusion block's base fee, P the transaction's priority-fee cap, and M its total fee cap per gas. When the fee cap covers the base fee, the effective tip is min(P, M - B); the execution price per gas is the base fee plus that effective tip. These relationships follow EIP-1559.

Our suggested estimator model therefore has separate fields for observed base fee, selected tip cap, selected total fee cap, and transaction gas limit. Give them explicit unit names in code. A field called gas should not sometimes mean gas units and sometimes mean gwei. Keep arithmetic in integer wei using BigInt or an equivalent integer type, and format decimal units only for display.

The transaction's actual execution fee is gas used multiplied by its effective gas price. Gas limit is a bound on execution units; a fee cap is a bound on price per unit. Ethereum's gas documentation explains those units and the wei-to-gwei relationship.

This article concerns ordinary Ethereum execution fees. Blob transactions and other networks can involve additional fee components, so we recommend separate estimators for those cases.

Choose a policy and label it

Here is an illustrative policy for product discussion: take a robust aggregate of recent middle-percentile tips, then set maxFeePerGas to twice the next-block base-fee value plus that chosen tip. The multiplier and percentile selection are suggestions, not protocol requirements. They provide headroom; they do not buy a guaranteed inclusion time.

Consider invented values of 20 gwei for the next-block base fee and 2 gwei for the chosen tip. That policy produces a 42 gwei total fee cap. If inclusion happens with a 21 gwei base fee and the full 2 gwei tip, the effective price is 23 gwei. The 42 gwei cap is not automatically the price paid.

For a hypothetical 50,000 gas used, the execution fee at 23 gwei is 1,150,000 gwei, or 0.00115 ETH. These numbers illustrate arithmetic only; they are not a current fee quote. A different execution path can consume a different amount of gas.

We recommend presenting the chosen policy beside the quote: sample age, selected tip, fee cap, gas-limit assumption, and maximum authorized budget. Avoid labels such as “confirmed in one block” unless your product has a separately justified basis for that statement.

Make stale and sparse data visible

Our recommendation is to expire quotes after a defined time or block advance, then refresh before asking the user to sign. If the application has been suspended in a browser tab, require a fresh sample. Carry the original budget forward so refreshing cannot silently authorize a higher spend.

Treat tip percentiles as historical observations. A historical 75th percentile is not a 75 percent probability of inclusion. For sparse or unusual samples, prefer an explicit fallback policy or an unavailable quote over silently manufacturing confidence.

Do not average gas-used ratios into a transaction gas estimate. Those ratios describe blocks. The gas needed for a particular transaction requires its own execution analysis. Similarly, summing historical base-fee entries does not produce the fee for one future transaction.

Evaluate outcomes without chasing every block

We suggest logging the estimator version, sample range, selected caps, and eventual receipt fields under an internal operation ID. Exclude signed payloads and credentials from routine analytics. Compare predicted spending with actual execution cost, and track how often quotes expire or require user review.

If a transaction remains pending, route it through an explicit replacement workflow. Do not let a fee refresher create new transactions automatically. A useful estimator supplies understandable inputs to a transaction policy; submission, replacement, and confirmation still need their own state management.

Share this article

Share on X

Review your account and post on X. Opening X or copying text does not send a post.

Explore the RPC docs →