From bf448fa74f1642e849f8a6836da645d1e9757e86 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 2 Sep 2020 13:32:35 +0300 Subject: [PATCH] Bridged tokens status fetcher refactoring --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/chain.ex | 219 +++++++++++------- .../lib/explorer/chain/block/reward.ex | 9 +- apps/explorer/lib/explorer/chain/token.ex | 1 + 4 files changed, 139 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4648f5300c..6f57907ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#3261](https://github.com/poanetwork/blockscout/pull/3261) - Bridged tokens table ### Fixes +- [#3276](https://github.com/poanetwork/blockscout/pull/3276) - Bridged tokens status/metadata fetcher refactoring - [#3264](https://github.com/poanetwork/blockscout/pull/3264) - Fix encoding of address output if function input exists - [#3259](https://github.com/poanetwork/blockscout/pull/3259), [#3269](https://github.com/poanetwork/blockscout/pull/3269) - Contract interaction: array input type parsing fix - [#3257](https://github.com/poanetwork/blockscout/pull/3257) - Contracts read/write: method_id instead function_name as a key diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 91a5ad8764..1541fe2f2c 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -3581,11 +3581,11 @@ defmodule Explorer.Chain do end @doc """ - Fetches bridges status for tokens. + Fetches bridged status for tokens and metadata. """ def fetch_tokens_bridged_status(token_addresses) do Enum.each(token_addresses, fn token_address_hash -> - created_from_factory_query = + created_from_int_tx_success_query = from( it in InternalTransaction, inner_join: t in assoc(it, :transaction), @@ -3593,104 +3593,145 @@ defmodule Explorer.Chain do where: t.status == ^1 ) - created_from_factory = - created_from_factory_query + created_from_int_tx_success = + created_from_int_tx_success_query |> Repo.one() - if created_from_factory do - multi_token_bridge_mediator = Application.get_env(:block_scout_web, :multi_token_bridge_mediator) - %{transaction_hash: transaction_hash} = created_from_factory + created_from_tx_query = + from( + t in Transaction, + where: t.created_contract_address_hash == ^token_address_hash + ) - if multi_token_bridge_mediator && multi_token_bridge_mediator !== "" do - {:ok, multi_token_bridge_mediator_hash} = Chain.string_to_address_hash(multi_token_bridge_mediator) + created_from_tx = + created_from_tx_query + |> Repo.all() + |> Enum.count() > 0 - created_by_amb_mediator_query = - from( - it in InternalTransaction, - where: it.transaction_hash == ^transaction_hash, - where: it.to_address_hash == ^multi_token_bridge_mediator_hash - ) + created_from_int_tx_query = + from( + it in InternalTransaction, + where: it.created_contract_address_hash == ^token_address_hash + ) - created_by_amb_mediator = - created_by_amb_mediator_query - |> Repo.all() - - if Enum.count(created_by_amb_mediator) > 0 do - json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) - # keccak 256 from getTokenInterfacesVersion() - get_token_interfaces_version_signature = "0x859ba28c" - # keccak 256 from foreignTokenAddress(address) - foreign_token_address_signature = "0x47ac7d6a" - # keccak 256 from bridgeContract() - bridge_contract_signature = "0xcd596583" - # keccak 256 from destinationChainId() - destination_chain_id_signature = "0xb0750611" - - token_address_hash_abi_encoded = - [token_address_hash.bytes] - |> TypeEncoder.encode([:address]) - |> Base.encode16() - - foreign_token_address_method = foreign_token_address_signature <> token_address_hash_abi_encoded - - with {:ok, _} <- - get_token_interfaces_version_signature - |> Contract.eth_call_request(token_address_hash, 1, nil, nil) - |> json_rpc(json_rpc_named_arguments), - {:ok, foreign_token_address_abi_encoded} <- - foreign_token_address_method - |> Contract.eth_call_request( - multi_token_bridge_mediator, - 1, - nil, - nil - ) - |> json_rpc(json_rpc_named_arguments), - {:ok, bridge_contract} <- - bridge_contract_signature - |> Contract.eth_call_request(multi_token_bridge_mediator_hash, 1, nil, nil) - |> json_rpc(json_rpc_named_arguments) do - "0x" <> foreign_token_address_no_prefix = foreign_token_address_abi_encoded - - <<_prefix::binary-size(24), foreign_token_address_hash_string_raw::binary()>> = - foreign_token_address_no_prefix - - foreign_token_address_hash_string = "0x" <> foreign_token_address_hash_string_raw - - {:ok, foreign_token_address_hash} = Chain.string_to_address_hash(foreign_token_address_hash_string) - - "0x" <> bridge_contract_no_prefix = bridge_contract - <<_prefix::binary-size(24), multi_token_bridge_hash_string_raw::binary()>> = bridge_contract_no_prefix - - multi_token_bridge_hash_string = "0x" <> multi_token_bridge_hash_string_raw - - {:ok, foreign_chain_id_abi_encoded} = - destination_chain_id_signature - |> Contract.eth_call_request(multi_token_bridge_hash_string, 1, nil, nil) - |> json_rpc(json_rpc_named_arguments) - - "0x" <> foreign_chain_id_abi_encoded_no_prefix = foreign_chain_id_abi_encoded - {foreign_chain_id, _} = Integer.parse(foreign_chain_id_abi_encoded_no_prefix, 16) - - set_bridged_token_metadata(token_address_hash, %{ - foreign_chain_id: foreign_chain_id, - foreign_token_address_hash: foreign_token_address_hash - }) - - set_token_bridged_status(token_address_hash, true) - end - else - set_token_bridged_status(token_address_hash, false) - end - end - else - set_token_bridged_status(token_address_hash, false) + created_from_int_tx = + created_from_int_tx_query + |> Repo.all() + |> Enum.count() > 0 + + cond do + created_from_tx -> + set_token_bridged_status(token_address_hash, false) + + created_from_int_tx && !created_from_int_tx_success -> + set_token_bridged_status(token_address_hash, false) + + created_from_int_tx && created_from_int_tx_success -> + extract_bridged_token_metadata_wrapper(token_address_hash, created_from_int_tx_success) + + true -> + :ok end end) :ok end + defp extract_bridged_token_metadata_wrapper(token_address_hash, created_from_int_tx_success) do + multi_token_bridge_mediator = Application.get_env(:block_scout_web, :multi_token_bridge_mediator) + %{transaction_hash: transaction_hash} = created_from_int_tx_success + + if multi_token_bridge_mediator && multi_token_bridge_mediator !== "" do + {:ok, multi_token_bridge_mediator_hash} = Chain.string_to_address_hash(multi_token_bridge_mediator) + + created_by_amb_mediator_query = + from( + it in InternalTransaction, + where: it.transaction_hash == ^transaction_hash, + where: it.to_address_hash == ^multi_token_bridge_mediator_hash + ) + + created_by_amb_mediator = + created_by_amb_mediator_query + |> Repo.all() + + if Enum.count(created_by_amb_mediator) > 0 do + extract_bridged_token_metadata( + token_address_hash, + multi_token_bridge_mediator, + multi_token_bridge_mediator_hash + ) + else + set_token_bridged_status(token_address_hash, false) + end + end + end + + defp extract_bridged_token_metadata(token_address_hash, multi_token_bridge_mediator, multi_token_bridge_mediator_hash) do + json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) + # keccak 256 from getTokenInterfacesVersion() + get_token_interfaces_version_signature = "0x859ba28c" + # keccak 256 from foreignTokenAddress(address) + foreign_token_address_signature = "0x47ac7d6a" + # keccak 256 from bridgeContract() + bridge_contract_signature = "0xcd596583" + # keccak 256 from destinationChainId() + destination_chain_id_signature = "0xb0750611" + + token_address_hash_abi_encoded = + [token_address_hash.bytes] + |> TypeEncoder.encode([:address]) + |> Base.encode16() + + foreign_token_address_method = foreign_token_address_signature <> token_address_hash_abi_encoded + + with {:ok, _} <- + get_token_interfaces_version_signature + |> Contract.eth_call_request(token_address_hash, 1, nil, nil) + |> json_rpc(json_rpc_named_arguments), + {:ok, foreign_token_address_abi_encoded} <- + foreign_token_address_method + |> Contract.eth_call_request( + multi_token_bridge_mediator, + 1, + nil, + nil + ) + |> json_rpc(json_rpc_named_arguments), + {:ok, bridge_contract} <- + bridge_contract_signature + |> Contract.eth_call_request(multi_token_bridge_mediator_hash, 1, nil, nil) + |> json_rpc(json_rpc_named_arguments) do + "0x" <> foreign_token_address_no_prefix = foreign_token_address_abi_encoded + + <<_prefix::binary-size(24), foreign_token_address_hash_string_raw::binary()>> = foreign_token_address_no_prefix + + foreign_token_address_hash_string = "0x" <> foreign_token_address_hash_string_raw + + {:ok, foreign_token_address_hash} = Chain.string_to_address_hash(foreign_token_address_hash_string) + + "0x" <> bridge_contract_no_prefix = bridge_contract + <<_prefix::binary-size(24), multi_token_bridge_hash_string_raw::binary()>> = bridge_contract_no_prefix + + multi_token_bridge_hash_string = "0x" <> multi_token_bridge_hash_string_raw + + {:ok, foreign_chain_id_abi_encoded} = + destination_chain_id_signature + |> Contract.eth_call_request(multi_token_bridge_hash_string, 1, nil, nil) + |> json_rpc(json_rpc_named_arguments) + + "0x" <> foreign_chain_id_abi_encoded_no_prefix = foreign_chain_id_abi_encoded + {foreign_chain_id, _} = Integer.parse(foreign_chain_id_abi_encoded_no_prefix, 16) + + set_bridged_token_metadata(token_address_hash, %{ + foreign_chain_id: foreign_chain_id, + foreign_token_address_hash: foreign_token_address_hash + }) + + set_token_bridged_status(token_address_hash, true) + end + end + defp set_token_bridged_status(token_address_hash, status) do target_token = Repo.get!(Token, token_address_hash) token = Changeset.change(target_token, bridged: status) diff --git a/apps/explorer/lib/explorer/chain/block/reward.ex b/apps/explorer/lib/explorer/chain/block/reward.ex index 753568eb9e..48ac03a1f5 100644 --- a/apps/explorer/lib/explorer/chain/block/reward.ex +++ b/apps/explorer/lib/explorer/chain/block/reward.ex @@ -171,8 +171,13 @@ defmodule Explorer.Chain.Block.Reward do if payout_key_hash == @empty_address do mining_key else - {:ok, payout_key} = Chain.string_to_address_hash(payout_key_hash) - payout_key + case Chain.string_to_address_hash(payout_key_hash) do + {:ok, payout_key} -> + payout_key + + _ -> + mining_key + end end else mining_key diff --git a/apps/explorer/lib/explorer/chain/token.ex b/apps/explorer/lib/explorer/chain/token.ex index e48ab5443b..84a774a314 100644 --- a/apps/explorer/lib/explorer/chain/token.ex +++ b/apps/explorer/lib/explorer/chain/token.ex @@ -35,6 +35,7 @@ defmodule Explorer.Chain.Token do * `contract_address_hash` - Address hash foreign key * `holder_count` - the number of `t:Explorer.Chain.Address.t/0` (except the burn address) that have a `t:Explorer.Chain.CurrentTokenBalance.t/0` `value > 0`. Can be `nil` when data not migrated. + * `bridged` - Flag for bridged tokens from other chain """ @type t :: %Token{ name: String.t(),