diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index bd520b4e70..316eddd8fa 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -74,6 +74,7 @@ defmodule Explorer.Chain do alias Explorer.Counters.{AddressesCounter, AddressesWithBalanceCounter} alias Explorer.Market.MarketHistoryCache alias Explorer.{PagingOptions, Repo} + alias Explorer.SmartContract.Reader alias Dataloader.Ecto, as: DataloaderEcto @@ -4337,6 +4338,52 @@ defmodule Explorer.Chain do end end + def combine_proxy_implementation_abi(address_hash, abi) do + implementation_method_abi = + abi + |> Enum.find(fn method -> + Map.get(method, "name") == "implementation" + end) + + implementation_abi = + if implementation_method_abi do + implementation_address = + case Reader.query_contract(address_hash, abi, %{ + "implementation" => [] + }) do + %{"implementation" => {:ok, [result]}} -> result + _ -> nil + end + + if implementation_address do + implementation_address_hash_string = "0x" <> Base.encode16(implementation_address, case: :lower) + + case Chain.string_to_address_hash(implementation_address_hash_string) do + {:ok, implementation_address_hash} -> + implementation_smart_contract = + implementation_address_hash + |> Chain.address_hash_to_smart_contract() + + if implementation_smart_contract do + implementation_smart_contract + |> Map.get(:abi) + else + [] + end + + _ -> + [] + end + else + [] + end + else + [] + end + + if Enum.empty?(implementation_abi), do: abi, else: implementation_abi ++ abi + end + defp format_tx_first_trace(first_trace, block_hash, json_rpc_named_arguments) do {:ok, to_address_hash} = if Map.has_key?(first_trace, :to_address_hash) do diff --git a/apps/explorer/lib/explorer/chain/log.ex b/apps/explorer/lib/explorer/chain/log.ex index 27899303f3..82c10c3eab 100644 --- a/apps/explorer/lib/explorer/chain/log.ex +++ b/apps/explorer/lib/explorer/chain/log.ex @@ -6,8 +6,8 @@ defmodule Explorer.Chain.Log do require Logger alias ABI.{Event, FunctionSelector} + alias Explorer{Chain, Repo} alias Explorer.Chain.{Address, Block, ContractMethod, Data, Hash, Transaction} - alias Explorer.Repo @required_attrs ~w(address_hash data block_hash index transaction_hash)a @optional_attrs ~w(first_topic second_topic third_topic fourth_topic type block_number)a @@ -121,8 +121,11 @@ defmodule Explorer.Chain.Log do """ def decode(_log, %Transaction{to_address: nil}), do: {:error, :no_to_address} - def decode(log, transaction = %Transaction{to_address: %{smart_contract: %{abi: abi}}}) when not is_nil(abi) do - with {:ok, selector, mapping} <- find_and_decode(abi, log, transaction), + def decode(log, transaction = %Transaction{to_address: %{smart_contract: %{abi: abi, address_hash: address_hash}}}) + when not is_nil(abi) do + full_abi = Chain.combine_proxy_implementation_abi(address_hash, abi) + + with {:ok, selector, mapping} <- find_and_decode(full_abi, log, transaction), identifier <- Base.encode16(selector.method_id, case: :lower), text <- function_call(selector.function, mapping), do: {:ok, identifier, text, mapping} diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index 5168f5db61..e4518c7349 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -28,7 +28,6 @@ defmodule Explorer.Chain.Transaction do } alias Explorer.Chain.Transaction.{Fork, Status} - alias Explorer.SmartContract.Reader @optional_attrs ~w(block_hash block_number created_contract_address_hash cumulative_gas_used earliest_processing_start error gas_used index created_contract_code_indexed_at status @@ -447,49 +446,7 @@ defmodule Explorer.Chain.Transaction do end defp do_decoded_input_data(data, abi, address_hash, hash) do - implementation_method_abi = - abi - |> Enum.find(fn method -> - Map.get(method, "name") == "implementation" - end) - - implementation_abi = - if implementation_method_abi do - implementation_address = - case Reader.query_contract(address_hash, abi, %{ - "implementation" => [] - }) do - %{"implementation" => {:ok, [result]}} -> result - _ -> nil - end - - if implementation_address do - implementation_address_hash_string = "0x" <> Base.encode16(implementation_address, case: :lower) - - case Chain.string_to_address_hash(implementation_address_hash_string) do - {:ok, implementation_address_hash} -> - implementation_smart_contract = - implementation_address_hash - |> Chain.address_hash_to_smart_contract() - - if implementation_smart_contract do - implementation_smart_contract - |> Map.get(:abi) - else - [] - end - - _ -> - [] - end - else - [] - end - else - [] - end - - full_abi = if Enum.empty?(implementation_abi), do: abi, else: implementation_abi ++ abi + full_abi = Chain.combine_proxy_implementation_abi(address_hash, abi) with {:ok, {selector, values}} <- find_and_decode(full_abi, data, hash), {:ok, mapping} <- selector_mapping(selector, values, hash),