Skip to content

Commit 9b3c73a

Browse files
shamardyclaude
andcommitted
fix(eth): use next-block base fee in simple EIP-1559 fee estimator
The simple fee-history estimator read `baseFeePerGas.first()`, which is the oldest block of the eth_feeHistory window, not the latest: the array is ordered oldest to newest and carries one extra trailing entry with the next block's base fee. On chains with fast blocks (Gnosis: 5s), the base fee can grow up to 12.5% per block, so a 5-block-stale base fee made max_fee_per_gas fall below the current base fee during fee spikes. Nethermind >= 1.36.0 strictly validates maxFeePerGas >= baseFee in eth_estimateGas when fee fields are passed, rejecting such requests and breaking order posting / trade preimage on Gnosis. Use `.last()` (the next block's base fee on spec-compliant clients, or the newest mined block on clients that omit the extra entry, e.g. Avalanche and Fantom) and match Nethermind's pre-1.38.0 error message "miner premium is negative" so it maps to GasFeeCapBelowBaseFee instead of a raw transport error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent e686ef3 commit 9b3c73a

2 files changed

Lines changed: 10 additions & 4 deletions

File tree

mm2src/coins/eth.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7562,6 +7562,8 @@ async fn get_eth_gas_details_from_withdraw_fee(
75627562
return MmError::err(EthGasDetailsErr::AmountTooLow { amount, threshold });
75637563
} else if error_str.contains("fee cap less than block base fee")
75647564
|| error_str.contains("max fee per gas less than block base fee")
7565+
// Nethermind < 1.38.0 reports a fee cap below the base fee with this message
7566+
|| error_str.contains("miner premium is negative")
75657567
{
75667568
if let Some((user_cap, required_base)) = parse_fee_cap_error(&error_str) {
75677569
// The RPC error gives fee values in wei. Convert to Gwei (9 decimals) for the user.

mm2src/coins/eth/fee_estimation/eip1559/simple.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,16 @@ impl FeePerGasSimpleEstimator {
133133

134134
/// estimate priority fees by fee history
135135
fn calculate_with_history(coin: &EthCoin, fee_history: &FeeHistoryResult) -> Web3RpcResult<FeePerGasEstimated> {
136-
// For estimation of max fee and max priority fee we use latest block base_fee but adjusted.
137-
// Apparently for this simple fee estimator for assured high priority we should assume
138-
// that the real base_fee may go up by 1,25 (i.e. if the block is full). This is covered by high priority ADJUST_MAX_FEE multiplier
136+
// For estimation of max fee and max priority fee we use the next block base_fee but adjusted.
137+
// `eth_feeHistory` returns `baseFeePerGas` ordered oldest to newest with one extra trailing entry
138+
// for the next (pending) block, so the last element is the most recent value available.
139+
// Note that some non-mainline clients (e.g. Avalanche, Fantom) omit the extra next-block entry,
140+
// in which case the last element is the newest mined block's base fee.
141+
// The ADJUST_BASE_FEE multipliers then add headroom on top in case the base fee keeps growing
142+
// (it can go up by 12.5% per block if blocks are full) until the tx is included.
139143
let latest_base_fee = fee_history
140144
.base_fee_per_gas
141-
.first()
145+
.last()
142146
.cloned()
143147
.unwrap_or_else(|| U256::from(0));
144148
let latest_base_fee_dec = wei_to_gwei_decimal(latest_base_fee).unwrap_or_else(|_| BigDecimal::from(0));

0 commit comments

Comments
 (0)