diff --git a/apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex b/apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex index bc9b590538..6e52a045d5 100644 --- a/apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex +++ b/apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex @@ -92,11 +92,7 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do from_block_query = max(from_block_acc, from_block_actual) - average_block_time = - case AverageBlockTime.average_block_time() do - {:error, _} -> nil - average_block_time -> average_block_time |> Duration.to_milliseconds() - end + average_block_time = get_average_block_time() fee_query = from( @@ -186,11 +182,26 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do defp merge_gas_prices(new, acc, from_block), do: Enum.take_while(new ++ acc, &(&1.block_number > from_block)) defp process_fee_data_from_db([]) do - %{ - slow: nil, - average: nil, - fast: nil - } + case Block.next_block_base_fee_per_gas() do + %Decimal{} = base_fee -> + base_fee_wei = base_fee |> Wei.from(:wei) + exchange_rate = Market.get_coin_exchange_rate() + + average_block_time = get_average_block_time() + + %{ + slow: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0), + average: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0), + fast: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0) + } + + _ -> + %{ + slow: nil, + average: nil, + fast: nil + } + end end defp process_fee_data_from_db(fees) do @@ -223,13 +234,12 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do {gas_price(slow_gas_price), gas_price(average_gas_price), gas_price(fast_gas_price), nil} end - exchange_rate_from_db = Market.get_coin_exchange_rate() + exchange_rate = Market.get_coin_exchange_rate() %{ - slow: compose_gas_price(slow_fee, slow_time, exchange_rate_from_db, base_fee_wei, slow_priority_fee_per_gas), - average: - compose_gas_price(average_fee, average_time, exchange_rate_from_db, base_fee_wei, average_priority_fee_per_gas), - fast: compose_gas_price(fast_fee, fast_time, exchange_rate_from_db, base_fee_wei, fast_priority_fee_per_gas) + slow: compose_gas_price(slow_fee, slow_time, exchange_rate, base_fee_wei, slow_priority_fee_per_gas), + average: compose_gas_price(average_fee, average_time, exchange_rate, base_fee_wei, average_priority_fee_per_gas), + fast: compose_gas_price(fast_fee, fast_time, exchange_rate, base_fee_wei, fast_priority_fee_per_gas) } end @@ -251,15 +261,27 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do {key, value} -> value = if is_list(value), do: value, else: [value] count = Enum.count(value) - {key, value |> Enum.reduce(Decimal.new(0), &Decimal.add/2) |> Decimal.div(count)} + + value = + value + |> Enum.reduce(Decimal.new(0), fn + fee, sum when is_float(fee) -> + fee |> Decimal.from_float() |> Decimal.add(sum) + + fee, sum -> + Decimal.add(sum, fee) + end) + |> Decimal.div(count) + + {key, value} end) end - defp compose_gas_price(fee, time, exchange_rate_from_db, base_fee, priority_fee) do + defp compose_gas_price(fee, time, exchange_rate, base_fee, priority_fee) do %{ price: fee |> format_wei(), time: time && time |> Decimal.to_float(), - fiat_price: fiat_fee(fee, exchange_rate_from_db), + fiat_price: fiat_fee(fee, exchange_rate), base_fee: base_fee |> format_wei(), priority_fee: base_fee && priority_fee && priority_fee |> Decimal.new() |> Wei.from(:wei) |> format_wei(), priority_fee_wei: base_fee && priority_fee && priority_fee |> Decimal.new() |> Decimal.round(), @@ -358,4 +380,11 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do end defp async_task_on_deletion(_data), do: nil + + defp get_average_block_time do + case AverageBlockTime.average_block_time() do + {:error, :disabled} -> nil + average_block_time -> average_block_time |> Duration.to_milliseconds() + end + end end diff --git a/apps/explorer/test/explorer/chain/cache/gas_price_oracle_test.exs b/apps/explorer/test/explorer/chain/cache/gas_price_oracle_test.exs index 3fc1493ed2..d048d056c2 100644 --- a/apps/explorer/test/explorer/chain/cache/gas_price_oracle_test.exs +++ b/apps/explorer/test/explorer/chain/cache/gas_price_oracle_test.exs @@ -90,6 +90,53 @@ defmodule Explorer.Chain.Cache.GasPriceOracleTest do }}, []} = GasPriceOracle.get_average_gas_price(2, 35, 60, 90) end + test "returns base fee only gas estimation if there is no recent transactions with non-zero gas price" do + block1 = + insert(:block, + number: 100, + hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391", + base_fee_per_gas: 100 + ) + + block2 = + insert(:block, + number: 101, + hash: "0x76c3da57334fffdc66c0d954dce1a910fcff13ec889a13b2d8b0b6e9440ce729", + base_fee_per_gas: 100 + ) + + :transaction + |> insert( + status: :ok, + block_hash: block1.hash, + block_number: block1.number, + cumulative_gas_used: 884_322, + gas_used: 106_025, + index: 0, + gas_price: 0, + hash: "0xac2a7dab94d965893199e7ee01649e2d66f0787a4c558b3118c09e80d4df8269" + ) + + :transaction + |> insert( + status: :ok, + block_hash: block2.hash, + block_number: block2.number, + cumulative_gas_used: 884_322, + gas_used: 106_025, + index: 0, + gas_price: 0, + hash: "0x5d5c2776f96704e7845f7d3c1fbba6685ab6efd6f82b6cd11d549f3b3a46bd03" + ) + + assert {{:ok, + %{ + average: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01}, + fast: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01}, + slow: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01} + }}, []} = GasPriceOracle.get_average_gas_price(2, 35, 60, 90) + end + test "returns the same percentile values if gas price is the same over transactions" do block1 = insert(:block, number: 100, hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391") block2 = insert(:block, number: 101, hash: "0x76c3da57334fffdc66c0d954dce1a910fcff13ec889a13b2d8b0b6e9440ce729")