A transaction can stay pending even when its fee cap covers the next block's base fee. If its priority tip trails recent blocks, a deadline payment can miss its window.
eth_feeHistory gives you recent effective tips and the derived base fee for the next block. This guide uses those values to quote an EIP-1559 transaction, reject stale samples, and choose a fee policy for urgent sends.
For the fee model itself, see the Ethereum gas fees primer.
Read the fee history response
EIP-1559 separates the base fee from the priority fee. The base fee is burned. The proposer receives the effective priority fee. maxFeePerGas caps their sum; setting a high cap does not make you pay the full cap.
Request 20 blocks and three tip percentiles from your Ethereum endpoint:
curl -sS https://api-ethereum-mainnet-erigon.n.dwellir.com/YOUR_API_KEY \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_feeHistory",
"params": ["0x14", "latest", [10, 50, 75]]
}'
The Execution API definition specifies these response fields:
| Field | What it tells you |
|---|---|
baseFeePerGas | One value per returned block, plus the derived base fee for the next block. Use the last element for the fee cap. |
reward | One row per returned block. Each row contains the requested effective tip percentiles, weighted by gas used. |
gasUsedRatio | Gas used divided by the block gas limit. On Ethereum, values above 0.5 raise the next base fee. |
oldestBlock | The first block in the returned range. Add the number of returned rows minus one to find the newest block. |
Clients can return fewer blocks than requested. Read the last element of baseFeePerGas, not baseFeePerGas[20]. Check that the arrays have the expected lengths before using the quote. Treat an RPC error or a missing reward array as a failed sample.

Choose a tip and fee cap
Each reward row describes transactions included in one block. It does not describe the pending transaction pool or promise that the same tip will clear the next block. A high percentile can reflect a short spike. A low percentile can lag a sudden rise.
A starting policy is to take the median p50 tip from nonempty blocks among the five newest rows. Use p75 from those rows for an urgent transaction. Compare inclusion time and actual tips paid before changing either choice.
Exclude an empty block when calculating the median. The API returns zero rewards for an empty block. Keep a zero tip from a nonempty block; it is an observed value. If no usable rows remain, reject the sample and obtain a fresh quote.
nextBaseFee = last(baseFeePerGas)
tip = median(chosen percentile from nonempty blocks in the five newest rows)
maxPriorityFeePerGas = tip
maxFeePerGas = 2 * nextBaseFee + tip
The 2 * nextBaseFee term is a fee-cap buffer, not an estimate of what you will pay. Under EIP-1559, the base fee can rise by at most 12.5% per full block. This buffer covers several such increases while the transaction waits. It cannot guarantee inclusion if competing tips rise.
Use integer wei throughout. Apply a tip ceiling and check maxFeePerGas * gasLimit against your transaction fee budget before signing. Recalculate both fields if the quote expires.
Reject a stale quote
eth_maxPriorityFeePerGas is a node's single suggested tip. It is useful for comparison, but its value has no attached history or freshness window. Caching either method's result across several new blocks can leave your transaction priced for an old market.
Calculate the newest sampled block as oldestBlock + gasUsedRatio.length - 1. Compare it with eth_blockNumber when you sign. For a deadline transaction, a starting rule is to refresh if the sample is more than one block behind the current head. Set the threshold from your own inclusion data.
HTTP requests can be fresh if you make one after each new head. A slow polling interval is the source of lag. A WebSocket newHeads subscription can trigger the same refresh, but the fee calculation still uses a current RPC response.

The latest block seen by one RPC backend can differ briefly from another's. A load-balanced endpoint can route sampling and submission to different nodes. Use the returned block number and age limit even when both calls use one endpoint.
Keep external gas quotes separate
A public gas API may use a different block window, percentile, or update interval. Its "high" tier cannot replace the p75 value in your own response without knowing that policy. Check units too: JSON-RPC fee values use wei, while gas dashboards often display gwei.
Use the fee history response that supplies your signing inputs. An external quote can trigger an alert when the two disagree, but it cannot tell you which source is current without its block number and update time. Re-query before changing the transaction fee.
This policy targets Ethereum mainnet. Other EVM networks can use different fee rules or transaction ordering. Do not carry Ethereum tip thresholds over to a layer 2 without checking that network's behavior.
Set a deadline policy before sending
A stale sample and an expensive fresh sample need different responses. Raising a tip derived from stale data does not repair the stale quote.
| Condition | Action |
|---|---|
| Sample is missing, malformed, or older than the age limit | Refresh. If it still fails, pause the deadline send and alert. |
| Sample is fresh and the deadline is close | Use the urgent tip percentile, subject to the configured fee budget. |
| Fresh quote exceeds the fee budget | Pause and alert. Do not silently remove the cap. |
| Transaction remains pending | Fetch a fresh quote before replacement. Keep the nonce and satisfy your node's replacement rules. |

Record the sample block, selected percentile, tip, fee cap, and inclusion block. Those values let you measure late transactions and overpayment before changing the window or tip policy.
Dwellir's Ethereum mainnet endpoint supports the standard JSON-RPC request shown above. Each eth_feeHistory call counts as one response under account rate limits. You can create an account to run the oracle against your own endpoint.


