Merge pull request #3282 from poanetwork/vb-bridged_tokens_custom_metadata

Import bridged tokens custom metadata
pull/3285/head
Victor Baranov 4 years ago committed by GitHub
commit 093c25096e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 1
      apps/block_scout_web/config/config.exs
  3. 5
      apps/block_scout_web/lib/block_scout_web/templates/tokens/overview/_details.html.eex
  4. 12
      apps/block_scout_web/priv/gettext/default.pot
  5. 12
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  6. 164
      apps/explorer/lib/explorer/chain.ex
  7. 6
      apps/explorer/lib/explorer/chain/bridged_token.ex
  8. 9
      apps/explorer/priv/repo/migrations/20200904075501_add_bridged_token_custom_metadata.exs
  9. 8
      apps/indexer/lib/indexer/set_bridged_metadata_for_tokens.ex
  10. 4
      apps/indexer/lib/indexer/supervisor.ex

@ -1,6 +1,7 @@
## Current
### Features
- [#3282](https://github.com/poanetwork/blockscout/pull/3282) - Import bridged tokens custom metadata
- [#3281](https://github.com/poanetwork/blockscout/pull/3281) - Write contract: display currently connected address
- [#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

@ -36,6 +36,7 @@ config :block_scout_web,
apps_menu: if(System.get_env("APPS_MENU", "false") == "true", do: true, else: false),
external_apps: System.get_env("EXTERNAL_APPS"),
multi_token_bridge_mediator: System.get_env("MULTI_TOKEN_BRIDGE_MEDIATOR"),
foreign_json_rpc: System.get_env("FOREIGN_JSON_RPC"),
gas_price: System.get_env("GAS_PRICE", nil)
config :block_scout_web, BlockScoutWeb.Counters.BlocksIndexedCounter, enabled: true

@ -52,6 +52,11 @@
<a data-test="original_token_contract_address" href=<%= foreign_bridged_token_explorer_link(@token) %> target="_blank">View Original Token <span class="external-token-icon"><%= render BlockScoutWeb.IconsView, "_external_link.html" %></span></a>
<% end %>
</div>
<div style="margin-top: 15px; font-size: 12px;">
<%= if Map.has_key?(@token, :custom_metadata) do %>
<%= @token.custom_metadata %>
<% end %>
</div>
<% end %>
</h1>

@ -1177,7 +1177,7 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:51
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:101
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:116
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:121
msgid "QR Code"
msgstr ""
@ -1447,7 +1447,7 @@ msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:86
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:91
msgid "Total Supply"
msgstr ""
@ -1604,7 +1604,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:16
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:20
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:66
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:71
msgid "View Contract"
msgstr ""
@ -1718,8 +1718,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:142
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:102
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:110
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:117
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:125
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:122
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:130
msgid "Close"
msgstr ""
@ -1736,7 +1736,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:76
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:74
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:79
msgid "Decimals"
msgstr ""

@ -1177,7 +1177,7 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:51
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:101
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:116
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:121
msgid "QR Code"
msgstr ""
@ -1447,7 +1447,7 @@ msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:86
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:91
msgid "Total Supply"
msgstr ""
@ -1604,7 +1604,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:16
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:20
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:66
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:71
msgid "View Contract"
msgstr ""
@ -1718,8 +1718,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:142
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:102
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:110
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:117
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:125
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:122
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:130
msgid "Close"
msgstr ""
@ -1736,7 +1736,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:76
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:74
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:79
msgid "Decimals"
msgstr ""

@ -3581,9 +3581,9 @@ defmodule Explorer.Chain do
end
@doc """
Fetches bridged status for tokens and metadata.
Fetches bridged tokens metadata.
"""
def fetch_tokens_bridged_status(token_addresses) do
def fetch_bridged_tokens_metadata(token_addresses) do
Enum.each(token_addresses, fn token_address_hash ->
created_from_int_tx_success_query =
from(
@ -3723,9 +3723,15 @@ defmodule Explorer.Chain do
"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_json_rpc = Application.get_env(:block_scout_web, :foreign_json_rpc)
custom_metadata =
get_bridged_token_custom_metadata(foreign_token_address_hash, json_rpc_named_arguments, foreign_json_rpc)
insert_bridged_token_metadata(token_address_hash, %{
foreign_chain_id: foreign_chain_id,
foreign_token_address_hash: foreign_token_address_hash
foreign_token_address_hash: foreign_token_address_hash,
custom_metadata: custom_metadata
})
set_token_bridged_status(token_address_hash, true)
@ -3739,21 +3745,163 @@ defmodule Explorer.Chain do
Repo.update(token)
end
defp set_bridged_token_metadata(token_address_hash, %{
defp insert_bridged_token_metadata(token_address_hash, %{
foreign_chain_id: foreign_chain_id,
foreign_token_address_hash: foreign_token_address_hash
foreign_token_address_hash: foreign_token_address_hash,
custom_metadata: custom_metadata
}) do
{:ok, _} =
Repo.insert(
%BridgedToken{
home_token_contract_address_hash: token_address_hash,
foreign_chain_id: foreign_chain_id,
foreign_token_contract_address_hash: foreign_token_address_hash
foreign_token_contract_address_hash: foreign_token_address_hash,
custom_metadata: custom_metadata
},
on_conflict: :nothing
)
end
# get_bridged_token_custom_metadata function currently gets Balancer token composite tokens with their weights
# from foreign chain
defp get_bridged_token_custom_metadata(foreign_token_address_hash, json_rpc_named_arguments, foreign_json_rpc)
when not is_nil(foreign_json_rpc) and foreign_json_rpc !== "" do
eth_call_foreign_json_rpc_named_arguments =
compose_foreign_json_rpc_named_arguments(json_rpc_named_arguments, foreign_json_rpc)
# keccak 256 from getCurrentTokens()
get_current_tokens_signature = "0xcc77828d"
case get_current_tokens_signature
|> Contract.eth_call_request(foreign_token_address_hash, 1, nil, nil)
|> json_rpc(eth_call_foreign_json_rpc_named_arguments) do
{:ok, "0x"} ->
nil
{:ok, balancer_current_tokens_encoded} ->
[balancer_current_tokens] =
balancer_current_tokens_encoded
|> String.trim_leading("0x")
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw([{:array, :address}])
bridged_token_custom_metadata =
parse_bridged_token_custom_metadata(
balancer_current_tokens,
eth_call_foreign_json_rpc_named_arguments,
foreign_token_address_hash
)
if is_map(bridged_token_custom_metadata),
do: "#{Map.get(bridged_token_custom_metadata, :tokens)} #{Map.get(bridged_token_custom_metadata, :weights)}",
else: nil
_ ->
nil
end
end
defp get_bridged_token_custom_metadata(_foreign_token_address_hash, _json_rpc_named_arguments, foreign_json_rpc)
when is_nil(foreign_json_rpc) do
nil
end
defp get_bridged_token_custom_metadata(_foreign_token_address_hash, _json_rpc_named_arguments, foreign_json_rpc)
when foreign_json_rpc == "" do
nil
end
defp compose_foreign_json_rpc_named_arguments(json_rpc_named_arguments, foreign_json_rpc) do
{_, eth_call_foreign_json_rpc_named_arguments} =
Keyword.get_and_update(json_rpc_named_arguments, :transport_options, fn transport_options ->
{_, updated_transport_options} =
update_transport_options_set_foreign_json_rpc(transport_options, foreign_json_rpc)
{transport_options, updated_transport_options}
end)
eth_call_foreign_json_rpc_named_arguments
end
defp update_transport_options_set_foreign_json_rpc(transport_options, foreign_json_rpc) do
Keyword.get_and_update(transport_options, :method_to_url, fn method_to_url ->
{_, updated_method_to_url} =
Keyword.get_and_update(method_to_url, :eth_call, fn eth_call ->
{eth_call, foreign_json_rpc}
end)
{method_to_url, updated_method_to_url}
end)
end
defp parse_bridged_token_custom_metadata(
balancer_current_tokens,
eth_call_foreign_json_rpc_named_arguments,
foreign_token_address_hash
) do
balancer_current_tokens
|> Enum.reduce(%{:tokens => "", :weights => ""}, fn balancer_token_bytes, acc ->
balancer_token_hash_without_0x =
balancer_token_bytes
|> Base.encode16(case: :lower)
balancer_token_hash = "0x" <> balancer_token_hash_without_0x
# 95d89b41 = keccak256(symbol())
symbol_signature = "95d89b41"
{:ok, symbol_encoded} =
symbol_signature
|> Contract.eth_call_request(balancer_token_hash, 1, nil, nil)
|> json_rpc(eth_call_foreign_json_rpc_named_arguments)
[symbol] =
symbol_encoded
|> String.trim_leading("0x")
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw([:string])
# f1b8a9b7 = keccak256(getNormalizedWeight(address))
get_normalized_weight_signature = "f1b8a9b7"
get_normalized_weight_arg_abi_encoded =
[balancer_token_bytes]
|> TypeEncoder.encode([:address])
|> Base.encode16(case: :lower)
get_normalized_weight_abi_encoded = get_normalized_weight_signature <> get_normalized_weight_arg_abi_encoded
{:ok, normalized_weight_encoded} =
get_normalized_weight_abi_encoded
|> Contract.eth_call_request(foreign_token_address_hash, 1, nil, nil)
|> json_rpc(eth_call_foreign_json_rpc_named_arguments)
[normalized_weight] =
normalized_weight_encoded
|> String.trim_leading("0x")
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw([{:uint, 256}])
normalized_weight_to_100_perc = 100 * normalized_weight
normalized_weight_in_perc =
normalized_weight_to_100_perc
|> div(1_000_000_000_000_000_000)
current_tokens = Map.get(acc, :tokens)
current_weights = Map.get(acc, :weights)
tokens_value = if current_tokens == "", do: symbol, else: current_tokens <> "/" <> symbol
weights_value =
if current_weights == "",
do: "#{normalized_weight_in_perc}",
else: current_weights <> "/" <> "#{normalized_weight_in_perc}"
%{:tokens => tokens_value, :weights => weights_value}
end)
end
@doc """
Fetches a `t:Token.t/0` by an address hash.
@ -3790,11 +3938,13 @@ defmodule Explorer.Chain do
[%Token{} = token, %BridgedToken{} = bridged_token] ->
foreign_token_contract_address_hash = Map.get(bridged_token, :foreign_token_contract_address_hash)
foreign_chain_id = Map.get(bridged_token, :foreign_chain_id)
custom_metadata = Map.get(bridged_token, :custom_metadata)
extended_token =
token
|> Map.put(:foreign_token_contract_address_hash, foreign_token_contract_address_hash)
|> Map.put(:foreign_chain_id, foreign_chain_id)
|> Map.put(:custom_metadata, custom_metadata)
{:ok, extended_token}

@ -20,7 +20,8 @@ defmodule Explorer.Chain.BridgedToken do
foreign_chain_id: Decimal.t(),
foreign_token_contract_address_hash: Hash.Address.t(),
home_token_contract_address: %Ecto.Association.NotLoaded{} | Address.t(),
home_token_contract_address_hash: Hash.Address.t()
home_token_contract_address_hash: Hash.Address.t(),
custom_metadata: String.t()
}
@derive {Poison.Encoder,
@ -43,6 +44,7 @@ defmodule Explorer.Chain.BridgedToken do
schema "bridged_tokens" do
field(:foreign_chain_id, :decimal)
field(:foreign_token_contract_address_hash, Hash.Address)
field(:custom_metadata, :string)
belongs_to(
:home_token_contract_address,
@ -57,7 +59,7 @@ defmodule Explorer.Chain.BridgedToken do
end
@required_attrs ~w(home_token_contract_address_hash)a
@optional_attrs ~w(foreign_chain_id foreign_token_contract_address_hash)a
@optional_attrs ~w(foreign_chain_id foreign_token_contract_address_hash custom_metadata)a
@doc false
def changeset(%BridgedToken{} = bridged_token, params \\ %{}) do

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Migrations.AddBridgedTokenCustomMetadata do
use Ecto.Migration
def change do
alter table(:bridged_tokens) do
add(:custom_metadata, :string, null: true)
end
end
end

@ -1,4 +1,4 @@
defmodule Indexer.SetBridgedStatusForTokens do
defmodule Indexer.SetBridgedMetadataForTokens do
@moduledoc """
Peiodically checks unprocessed tokens and sets bridged status.
"""
@ -34,15 +34,15 @@ defmodule Indexer.SetBridgedStatusForTokens do
{:ok, token_addresses} = Chain.unprocessed_token_addresses_to_reveal_bridged_tokens()
fetch_tokens_bridged_status(token_addresses)
fetch_bridged_tokens_metadata(token_addresses)
Process.send_after(self(), :reveal_unprocessed_tokens, interval)
{:noreply, state}
end
defp fetch_tokens_bridged_status(token_addresses) do
:ok = Chain.fetch_tokens_bridged_status(token_addresses)
defp fetch_bridged_tokens_metadata(token_addresses) do
:ok = Chain.fetch_bridged_tokens_metadata(token_addresses)
Logger.debug(fn -> "Bridged status fetched for tokens" end)
end

@ -5,7 +5,7 @@ defmodule Indexer.Supervisor do
use Supervisor
alias Indexer.{Block, PendingOpsCleaner, SetBridgedStatusForTokens}
alias Indexer.{Block, PendingOpsCleaner, SetBridgedMetadataForTokens}
alias Indexer.Block.{Catchup, Realtime}
alias Indexer.Fetcher.{
@ -133,7 +133,7 @@ defmodule Indexer.Supervisor do
all_fetchers =
if multi_token_bridge_mediator && multi_token_bridge_mediator !== "" do
[{SetBridgedStatusForTokens, [[], []]} | basic_fetchers]
[{SetBridgedMetadataForTokens, [[], []]} | basic_fetchers]
else
basic_fetchers
end

Loading…
Cancel
Save