Decode log in proxy contracts

pull/3153/head
Victor Baranov 5 years ago
parent 485a262d91
commit 102b80fada
  1. 47
      apps/explorer/lib/explorer/chain.ex
  2. 9
      apps/explorer/lib/explorer/chain/log.ex
  3. 45
      apps/explorer/lib/explorer/chain/transaction.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

@ -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}

@ -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),

Loading…
Cancel
Save