Merge remote-tracking branch 'origin/master' into vb-nft-external-link

pull/3279/head
Victor Baranov 4 years ago
commit 9c20e1fd80
  1. 2
      CHANGELOG.md
  2. 2
      apps/block_scout_web/lib/block_scout_web/views/address_transaction_view.ex
  3. 2
      apps/block_scout_web/lib/block_scout_web/views/tokens/helpers.ex
  4. 2
      apps/block_scout_web/lib/block_scout_web/views/tokens/holder_view.ex
  5. 2
      apps/explorer/lib/explorer/accounts/accounts.ex
  6. 219
      apps/explorer/lib/explorer/chain.ex
  7. 9
      apps/explorer/lib/explorer/chain/block/reward.ex
  8. 1
      apps/explorer/lib/explorer/chain/token.ex
  9. 23
      apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
  10. 2
      apps/indexer/lib/indexer/fetcher.ex
  11. 2
      apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
  12. 2
      apps/indexer/lib/indexer/fetcher/pending_transaction.ex
  13. 2
      mix.lock

@ -2,11 +2,13 @@
### Features
- [#3279](https://github.com/poanetwork/blockscout/pull/3279) - NFT instance: link to the app
- [#3278](https://github.com/poanetwork/blockscout/pull/3278) - Support of fetching of NFT tokens metadata from IPFS
- [#3273](https://github.com/poanetwork/blockscout/pull/3273) - Update token metadata at burn/mint events
- [#3268](https://github.com/poanetwork/blockscout/pull/3268) - Token total supply on-demand fetcher
- [#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

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.AddressTransactionView do
use BlockScoutWeb, :view
alias Explorer.Chain.{Address}
alias Explorer.Chain.Address
def format_current_filter(filter) do
case filter do

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.Tokens.Helpers do
Helper functions for interacting with `t:BlockScoutWeb.Chain.Token` attributes.
"""
alias BlockScoutWeb.{CurrencyHelpers}
alias BlockScoutWeb.CurrencyHelpers
alias Explorer.Chain.{Address, Token}
@doc """

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.Tokens.HolderView do
use BlockScoutWeb, :view
alias BlockScoutWeb.Tokens.OverviewView
alias Explorer.Chain.{Token}
alias Explorer.Chain.Token
@doc """
Checks if the total supply percentage must be shown.

@ -5,7 +5,7 @@ defmodule Explorer.Accounts do
alias Comeonin.Bcrypt
alias Ecto.Changeset
alias Explorer.Accounts.{User}
alias Explorer.Accounts.User
alias Explorer.Accounts.User.{Authenticate, Registration}
alias Explorer.Repo

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

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

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

@ -8,6 +8,8 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
alias Explorer.SmartContract.Reader
alias HTTPoison.{Error, Response}
@token_uri "c87b56dd"
@abi [
%{
"type" => "function",
@ -38,7 +40,7 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
def fetch_metadata(contract_address_hash, token_id) do
# c87b56dd = keccak256(tokenURI(uint256))
contract_functions = %{"c87b56dd" => [token_id]}
contract_functions = %{@token_uri => [token_id]}
contract_address_hash
|> query_contract(contract_functions)
@ -49,26 +51,26 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
Reader.query_contract(contract_address_hash, @abi, contract_functions)
end
def fetch_json(%{"c87b56dd" => {:ok, [""]}}) do
def fetch_json(%{@token_uri => {:ok, [""]}}) do
{:ok, %{error: @no_uri_error}}
end
def fetch_json(%{"c87b56dd" => {:error, "(-32015) VM execution error."}}) do
def fetch_json(%{@token_uri => {:error, "(-32015) VM execution error."}}) do
{:ok, %{error: @no_uri_error}}
end
def fetch_json(%{"c87b56dd" => {:ok, ["http://" <> _ = token_uri]}}) do
def fetch_json(%{@token_uri => {:ok, ["http://" <> _ = token_uri]}}) do
fetch_metadata(token_uri)
end
def fetch_json(%{"c87b56dd" => {:ok, ["https://" <> _ = token_uri]}}) do
def fetch_json(%{@token_uri => {:ok, ["https://" <> _ = token_uri]}}) do
fetch_metadata(token_uri)
end
def fetch_json(%{"c87b56dd" => {:ok, ["data:application/json," <> json]}}) do
def fetch_json(%{@token_uri => {:ok, ["data:application/json," <> json]}}) do
decoded_json = URI.decode(json)
fetch_json(%{"c87b56dd" => {:ok, [decoded_json]}})
fetch_json(%{@token_uri => {:ok, [decoded_json]}})
rescue
e ->
Logger.debug(["Unknown metadata format #{inspect(json)}. error #{inspect(e)}"],
@ -78,7 +80,12 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
{:error, json}
end
def fetch_json(%{"c87b56dd" => {:ok, [json]}}) do
def fetch_json(%{@token_uri => {:ok, ["ipfs://ipfs/" <> ipfs_uid]}}) do
ipfs_url = "https://ipfs.io/ipfs/" <> ipfs_uid
fetch_metadata(ipfs_url)
end
def fetch_json(%{@token_uri => {:ok, [json]}}) do
{:ok, json} = decode_json(json)
check_type(json)

@ -50,7 +50,7 @@ defmodule Indexer.Fetcher do
end
end
def disabled?() do
def disabled? do
Application.get_env(:indexer, __MODULE__, [])[:disabled?] == true
end

@ -15,7 +15,7 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
import Ecto.Query, only: [from: 2]
import EthereumJSONRPC, only: [integer_to_quantity: 1]
alias EthereumJSONRPC.{FetchedBalances}
alias EthereumJSONRPC.FetchedBalances
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Address
alias Explorer.Chain.Address.{CoinBalance, CoinBalanceDaily}

@ -14,7 +14,7 @@ defmodule Indexer.Fetcher.PendingTransaction do
alias Ecto.Changeset
alias Explorer.Chain
alias Explorer.Chain.Cache.{Accounts}
alias Explorer.Chain.Cache.Accounts
alias Indexer.Fetcher.PendingTransaction
alias Indexer.Transform.Addresses

@ -20,7 +20,7 @@
"cors_plug": {:hex, :cors_plug, "2.0.0", "238ddb479f92b38f6dc1ae44b8d81f0387f9519101a6da442d543ab70ee0e482", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "118162367ef41448c9742ced8c8bc33ae2857d958d6b997e1db26402dd8c6f37"},
"cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
"cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
"credo": {:hex, :credo, "1.1.2", "02b6422f3e659eb74b05aca3c20c1d8da0119a05ee82577a82e6c2938bf29f81", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd9322e9d391251ca3c4fac10ff0ce86ea4b99b3d9b34526ee2a7baa5928167d"},
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"},
"csv": {:hex, :csv, "2.3.1", "9ce11eff5a74a07baf3787b2b19dd798724d29a9c3a492a41df39f6af686da0e", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "86626e1c89a4ad9a96d0d9c638f9e88c2346b89b4ba1611988594ebe72b5d5ee"},
"dataloader": {:hex, :dataloader, "1.0.7", "58351b335673cf40601429bfed6c11fece6ce7ad169b2ac0f0fe83e716587391", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "12bf66478e4a5085d09dc96932d058c206ee8c219cc7691d12a40dc35c8cefaa"},
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},

Loading…
Cancel
Save