feat: Celo API updates (#10629)

* fix: use atom for matching the `:chain_type`

* feat: add celo epoch number to `/api/v2/stats` response

* chore: display base fee in wei

* feat: add token info to base fee section

* fix: process review comments
pull/10673/head
Fedor Ivanov 3 months ago committed by GitHub
parent dcf88c0c81
commit acd60fb4bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex
  2. 46
      apps/block_scout_web/lib/block_scout_web/views/api/v2/celo_view.ex
  3. 6
      apps/explorer/lib/explorer/chain.ex
  4. 28
      apps/explorer/lib/explorer/chain/celo/reader.ex

@ -190,12 +190,18 @@ defmodule BlockScoutWeb.API.V2.StatsController do
end
end
"optimism" ->
:optimism ->
defp add_chain_type_fields(response) do
import Explorer.Counters.LastOutputRootSizeCounter, only: [fetch: 1]
response |> Map.put("last_output_root_size", fetch(@api_true))
end
:celo ->
defp add_chain_type_fields(response) do
import Explorer.Chain.Celo.Reader, only: [last_block_epoch_number: 0]
response |> Map.put("celo", %{"epoch_number" => last_block_epoch_number()})
end
_ ->
defp add_chain_type_fields(response), do: response
end

@ -14,7 +14,7 @@ defmodule BlockScoutWeb.API.V2.CeloView do
alias Explorer.Chain.Celo.Helper, as: CeloHelper
alias Explorer.Chain.Celo.{ElectionReward, EpochReward}
alias Explorer.Chain.Hash
alias Explorer.Chain.{Block, Transaction}
alias Explorer.Chain.{Block, Token, Transaction, Wei}
@address_params [
necessity_by_association: %{
@ -97,12 +97,14 @@ defmodule BlockScoutWeb.API.V2.CeloView do
end
def render("celo_base_fee.json", %Block{} = block) do
block.transactions
|> Block.burnt_fees(block.base_fee_per_gas)
|> Wei.cast()
|> case do
{:ok, base_fee} ->
# For the blocks, where both FeeHandler and Governance contracts aren't
# deployed, the base fee is not burnt, but refunded to transaction sender,
# so we return nil in this case.
base_fee = Block.burnt_fees(block.transactions, block.base_fee_per_gas)
fee_handler_base_fee_breakdown(
base_fee,
block.number
@ -111,6 +113,10 @@ defmodule BlockScoutWeb.API.V2.CeloView do
base_fee,
block.number
)
_ ->
nil
end
end
def render("celo_election_rewards.json", %{
@ -246,7 +252,7 @@ defmodule BlockScoutWeb.API.V2.CeloView do
# Get the breakdown of the base fee for the case when FeeHandler is a contract
# that receives the base fee.
@spec fee_handler_base_fee_breakdown(Decimal.t(), Block.block_number()) ::
@spec fee_handler_base_fee_breakdown(Wei.t(), Block.block_number()) ::
%{
:recipient => %{optional(String.t()) => any()},
:amount => float(),
@ -265,13 +271,14 @@ defmodule BlockScoutWeb.API.V2.CeloView do
{:ok, %{"address" => fee_beneficiary_address_hash}} <-
CeloCoreContracts.get_event(:fee_handler, :fee_beneficiary_set, block_number),
{:ok, %{"value" => burn_fraction_fixidity_lib}} <-
CeloCoreContracts.get_event(:fee_handler, :burn_fraction_set, block_number) do
CeloCoreContracts.get_event(:fee_handler, :burn_fraction_set, block_number),
{:ok, celo_token_address_hash} <- CeloCoreContracts.get_address(:celo_token, block_number) do
burn_fraction = burn_fraction_decimal(burn_fraction_fixidity_lib)
burnt_amount = Decimal.mult(base_fee, burn_fraction)
burnt_amount = Wei.mult(base_fee, burn_fraction)
burnt_percentage = Decimal.mult(burn_fraction, 100)
carbon_offsetting_amount = Decimal.sub(base_fee, burnt_amount)
carbon_offsetting_amount = Wei.sub(base_fee, burnt_amount)
carbon_offsetting_percentage = Decimal.sub(100, burnt_percentage)
celo_burn_address_hash_string = dead_address_hash_string()
@ -311,18 +318,25 @@ defmodule BlockScoutWeb.API.V2.CeloView do
}
)
celo_token = Token.get_by_contract_address_hash(celo_token_address_hash, api?: true)
%{
recipient: fee_handler_contract_address_info,
amount: base_fee,
token:
TokenView.render("token.json", %{
token: celo_token,
contract_address_hash: celo_token.contract_address_hash
}),
breakdown: [
%{
address: burn_address_info,
amount: Decimal.to_float(burnt_amount),
amount: burnt_amount,
percentage: Decimal.to_float(burnt_percentage)
},
%{
address: fee_beneficiary_address_info,
amount: Decimal.to_float(carbon_offsetting_amount),
amount: carbon_offsetting_amount,
percentage: Decimal.to_float(carbon_offsetting_percentage)
}
]
@ -337,7 +351,7 @@ defmodule BlockScoutWeb.API.V2.CeloView do
#
# Note that the base fee is not burnt in this case, but simply kept on the
# contract balance.
@spec governance_base_fee_breakdown(Decimal.t(), Block.block_number()) ::
@spec governance_base_fee_breakdown(Wei.t(), Block.block_number()) ::
%{
:recipient => %{optional(String.t()) => any()},
:amount => float(),
@ -353,7 +367,8 @@ defmodule BlockScoutWeb.API.V2.CeloView do
defp governance_base_fee_breakdown(base_fee, block_number) do
with {:ok, address_hash_string} when not is_nil(address_hash_string) <-
CeloCoreContracts.get_address(:governance, block_number),
{:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string) do
{:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, celo_token_address_hash} <- CeloCoreContracts.get_address(:celo_token, block_number) do
address =
address_hash
# todo: Querying database in the view is not a good practice. Consider
@ -370,9 +385,16 @@ defmodule BlockScoutWeb.API.V2.CeloView do
address_hash
)
celo_token = Token.get_by_contract_address_hash(celo_token_address_hash, api?: true)
%{
recipient: address_with_info,
amount: base_fee,
token:
TokenView.render("token.json", %{
token: celo_token,
contract_address_hash: celo_token.contract_address_hash
}),
breakdown: []
}
else

@ -2105,11 +2105,11 @@ defmodule Explorer.Chain do
{:error, :not_found}
"""
@spec max_consensus_block_number() :: {:ok, Block.block_number()} | {:error, :not_found}
def max_consensus_block_number do
@spec max_consensus_block_number(Keyword.t()) :: {:ok, Block.block_number()} | {:error, :not_found}
def max_consensus_block_number(options \\ []) do
Block
|> where(consensus: true)
|> Repo.aggregate(:max, :number)
|> select_repo(options).aggregate(:max, :number)
|> case do
nil -> {:error, :not_found}
number -> {:ok, number}

@ -9,11 +9,13 @@ defmodule Explorer.Chain.Celo.Reader do
only: [
select_repo: 1,
join_associations: 2,
default_paging_options: 0
default_paging_options: 0,
max_consensus_block_number: 1
]
alias Explorer.Chain.Cache.CeloCoreContracts
alias Explorer.Chain.Celo.ElectionReward
alias Explorer.Chain.Block
alias Explorer.Chain.Cache.{Blocks, CeloCoreContracts}
alias Explorer.Chain.Celo.{ElectionReward, Helper}
alias Explorer.Chain.{Hash, Token, Wei}
@election_reward_types ElectionReward.types()
@ -190,4 +192,24 @@ defmodule Explorer.Chain.Celo.Reader do
{reward_type_atom, Map.get(token_atom_to_token, token_atom)}
end)
end
@doc """
Retrieves the epoch number of the last fetched block.
"""
@spec last_block_epoch_number(Keyword.t()) :: Block.block_number() | nil
def last_block_epoch_number(options \\ []) do
block_number =
1
|> Blocks.atomic_take_enough()
|> case do
[%Block{number: number}] -> {:ok, number}
nil -> max_consensus_block_number(options)
end
|> case do
{:ok, number} -> number
_ -> nil
end
block_number && Helper.block_number_to_epoch_number(block_number)
end
end

Loading…
Cancel
Save