Merge pull request #3320 from poanetwork/vb-amb-tokens

Bridged tokens from AMB extensions support
pull/3325/head
Victor Baranov 4 years ago committed by GitHub
commit 5821f3af37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 1
      apps/block_scout_web/assets/css/app.scss
  3. 19
      apps/block_scout_web/assets/css/components/_label.scss
  4. 5
      apps/block_scout_web/config/config.exs
  5. 3
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/bridged_tokens_controller.ex
  6. 23
      apps/block_scout_web/lib/block_scout_web/templates/bridged_tokens/_tile.html.eex
  7. 1
      apps/block_scout_web/lib/block_scout_web/templates/bridged_tokens/index.html.eex
  8. 2
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  9. 19
      apps/block_scout_web/lib/block_scout_web/views/bridged_tokens_view.ex
  10. 4
      apps/block_scout_web/lib/block_scout_web/views/tokens_view.ex
  11. 260
      apps/explorer/lib/explorer/chain.ex
  12. 8
      apps/explorer/lib/explorer/chain/bridged_token.ex
  13. 9
      apps/explorer/priv/repo/migrations/20200929075625_add_bridged_token_type.exs
  14. 39
      apps/indexer/lib/indexer/set_amb_bridged_metadata_for_tokens.ex
  15. 8
      apps/indexer/lib/indexer/set_omni_bridged_metadata_for_tokens.ex
  16. 19
      apps/indexer/lib/indexer/supervisor.ex

@ -1,6 +1,7 @@
## Current ## Current
### Features ### Features
- [#3320](https://github.com/poanetwork/blockscout/pull/3320) - Bridged tokens from AMB extensions support
- [#3311](https://github.com/poanetwork/blockscout/pull/3311) - List of addresses with restricted access option - [#3311](https://github.com/poanetwork/blockscout/pull/3311) - List of addresses with restricted access option
- [#3293](https://github.com/poanetwork/blockscout/pull/3293) - Composite market cap for xDai: TokenBridge + OmniBridge - [#3293](https://github.com/poanetwork/blockscout/pull/3293) - Composite market cap for xDai: TokenBridge + OmniBridge
- [#3282](https://github.com/poanetwork/blockscout/pull/3282), [#3318](https://github.com/poanetwork/blockscout/pull/3318) - Import bridged tokens custom metadata - [#3282](https://github.com/poanetwork/blockscout/pull/3282), [#3318](https://github.com/poanetwork/blockscout/pull/3318) - Import bridged tokens custom metadata

@ -117,6 +117,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "components/_erc721_token_image_container"; @import "components/_erc721_token_image_container";
@import "components/_inventory_token_instance_image_container"; @import "components/_inventory_token_instance_image_container";
@import "components/_external_link"; @import "components/_external_link";
@import "components/_label";
@import "theme/dark-theme"; @import "theme/dark-theme";

@ -0,0 +1,19 @@
.bridged-token-label {
display: inline-block;
padding: 5px;
background: #f5f6fa;
color: #a3a9b5;
border-radius: 5px;
font-size: 10px;
&.right {
float: right;
}
&.omni {
background: $primary;
color: white;
}
&.amb {
background: $secondary;
color: white;
}
}

@ -36,8 +36,9 @@ config :block_scout_web,
api_url: System.get_env("API_URL"), api_url: System.get_env("API_URL"),
apps_menu: if(System.get_env("APPS_MENU", "false") == "true", do: true, else: false), apps_menu: if(System.get_env("APPS_MENU", "false") == "true", do: true, else: false),
external_apps: System.get_env("EXTERNAL_APPS"), external_apps: System.get_env("EXTERNAL_APPS"),
multi_token_bridge_mediator: System.get_env("MULTI_TOKEN_BRIDGE_MEDIATOR"), omni_bridge_mediator: System.get_env("OMNI_BRIDGE_MEDIATOR"),
foreign_json_rpc: System.get_env("FOREIGN_JSON_RPC"), amb_bridge_mediators: System.get_env("AMB_BRIDGE_MEDIATORS"),
foreign_json_rpc: System.get_env("FOREIGN_JSON_RPC", ""),
gas_price: System.get_env("GAS_PRICE", nil), gas_price: System.get_env("GAS_PRICE", nil),
restricted_list: System.get_env("RESTRICTED_LIST", nil), restricted_list: System.get_env("RESTRICTED_LIST", nil),
restricted_list_key: System.get_env("RESTRICTED_LIST_KEY", nil) restricted_list_key: System.get_env("RESTRICTED_LIST_KEY", nil)

@ -31,11 +31,12 @@ defmodule BlockScoutWeb.BridgedTokensController do
items = items =
tokens_page tokens_page
|> Enum.with_index(1) |> Enum.with_index(1)
|> Enum.map(fn {token, index} -> |> Enum.map(fn {[token, bridged_token], index} ->
View.render_to_string( View.render_to_string(
BridgedTokensView, BridgedTokensView,
"_tile.html", "_tile.html",
token: token, token: token,
bridged_token: bridged_token,
index: index index: index
) )
end) end)

@ -7,10 +7,33 @@
</td> </td>
<td class="stakes-td"> <td class="stakes-td">
<% token = token_display_name(@token) %> <% token = token_display_name(@token) %>
<div>
<%= link(token, <%= link(token,
to: token_path(BlockScoutWeb.Endpoint, :show, @token.contract_address_hash), to: token_path(BlockScoutWeb.Endpoint, :show, @token.contract_address_hash),
"data-test": "token_link", "data-test": "token_link",
class: "text-truncate") %> class: "text-truncate") %>
<%= if @bridged_token.type do %>
<div class="bridged-token-label right <%= @bridged_token.type %>"><%= String.upcase(@bridged_token.type) %></div>
<% end %>
<%= if owl_token_amb?(@token.contract_address.hash) do %>
<span
data-toggle="tooltip"
data-placement="top"
data-html="true"
title="<%= owl_token_amb_info() %>">
<i style="color: #f7b32b;" class="fa fa-info-circle ml-1" data-test="owl_info"></i>
</span>
<% end %>
<%= if owl_token_omni?(@token.contract_address.hash) do %>
<span
data-toggle="tooltip"
data-placement="top"
data-html="true"
title="<%= owl_token_omni_info() %>">
<i style="color: #f7b32b;" class="fa fa-info-circle ml-1" data-test="owl_info"></i>
</span>
<% end %>
</div>
</td> </td>
<td class="stakes-td"> <td class="stakes-td">
<%= render BlockScoutWeb.AddressView, <%= render BlockScoutWeb.AddressView,

@ -2,6 +2,7 @@
<div class="card"> <div class="card">
<div class="card-body" data-async-load data-async-listing="<%= @current_path %>"> <div class="card-body" data-async-load data-async-listing="<%= @current_path %>">
<h1 class="card-title"><%= gettext "Bridged Tokens" %></h1> <h1 class="card-title"><%= gettext "Bridged Tokens" %></h1>
<p class="card-subtitle">List of the tokens bridged through OmniBridge <span class="bridged-token-label omni">OMNI</span> and Arbitrary Message Bridge <span class="bridged-token-label amb">AMB</span> extensions</p>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -78,7 +78,7 @@
<%= gettext("Accounts") %> <%= gettext("Accounts") %>
<% end %> <% end %>
</li> </li>
<%= if Application.get_env(:block_scout_web, :multi_token_bridge_mediator) && Application.get_env(:block_scout_web, :multi_token_bridge_mediator) != "" do %> <%= if Application.get_env(:block_scout_web, :omni_bridge_mediator) && Application.get_env(:block_scout_web, :omni_bridge_mediator) != "" do %>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a href="#" role="button" id="navbarTokensDropdown" class="nav-link topnav-nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a href="#" role="button" id="navbarTokensDropdown" class="nav-link topnav-nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon"> <span class="nav-link-icon">

@ -3,10 +3,29 @@ defmodule BlockScoutWeb.BridgedTokensView do
alias Explorer.Chain.Token alias Explorer.Chain.Token
@owl_token_amb "0x0905Ab807F8FD040255F0cF8fa14756c1D824931"
@owl_token_omni "0x750eCf8c11867Ce5Dbc556592c5bb1E0C6d16538"
def decimals?(%Token{decimals: nil}), do: false def decimals?(%Token{decimals: nil}), do: false
def decimals?(%Token{decimals: _}), do: true def decimals?(%Token{decimals: _}), do: true
def token_display_name(%Token{name: nil}), do: "" def token_display_name(%Token{name: nil}), do: ""
def token_display_name(%Token{name: name}), do: name def token_display_name(%Token{name: name}), do: name
def owl_token_amb?(address_hash) do
to_string(address_hash) == String.downcase(@owl_token_amb)
end
def owl_token_omni?(address_hash) do
to_string(address_hash) == String.downcase(@owl_token_omni)
end
def owl_token_amb_info do
"<div class='token-bridge-market-cap-header'>Bridged through AMB extension OWL token, which supports <i>burnOwl</i> method.</div>"
end
def owl_token_omni_info do
"<div class='token-bridge-market-cap-header'>Bridged through OmniBridge OWL token. It doesn't support <i>burnOwl</i> method.</div>"
end
end end

@ -7,9 +7,9 @@ defmodule BlockScoutWeb.TokensView do
def decimals?(%Token{decimals: _}), do: true def decimals?(%Token{decimals: _}), do: true
def bridged_tokens_enabled? do def bridged_tokens_enabled? do
multi_token_bridge_mediator = Application.get_env(:block_scout_web, :multi_token_bridge_mediator) omni_bridge_mediator = Application.get_env(:block_scout_web, :omni_bridge_mediator)
multi_token_bridge_mediator && multi_token_bridge_mediator !== "" omni_bridge_mediator && omni_bridge_mediator !== ""
end end
def token_display_name(%Token{name: nil, symbol: nil}), do: "" def token_display_name(%Token{name: nil, symbol: nil}), do: ""

@ -24,6 +24,8 @@ defmodule Explorer.Chain do
import EthereumJSONRPC, only: [integer_to_quantity: 1, json_rpc: 2, fetch_block_internal_transactions: 2] import EthereumJSONRPC, only: [integer_to_quantity: 1, json_rpc: 2, fetch_block_internal_transactions: 2]
require Logger
alias ABI.{TypeDecoder, TypeEncoder} alias ABI.{TypeDecoder, TypeEncoder}
alias Ecto.Adapters.SQL alias Ecto.Adapters.SQL
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi}
@ -1820,11 +1822,19 @@ defmodule Explorer.Chain do
end end
defp fetch_top_bridged_tokens(paging_options) do defp fetch_top_bridged_tokens(paging_options) do
bridged_tokens_query =
from(bt in BridgedToken,
select: bt
)
base_query = base_query =
from(t in Token, from(t in Token,
left_join: bt in subquery(bridged_tokens_query),
on: t.contract_address_hash == bt.home_token_contract_address_hash,
where: t.total_supply > ^0, where: t.total_supply > ^0,
where: t.bridged, where: t.bridged,
order_by: [desc: t.holder_count, asc: t.name], order_by: [desc: t.holder_count, asc: t.name],
select: [t, bt],
preload: [:contract_address] preload: [:contract_address]
) )
@ -3581,9 +3591,62 @@ defmodule Explorer.Chain do
end end
@doc """ @doc """
Fetches bridged tokens metadata. Processes AMB tokens from mediators addresses provided
"""
def process_amb_tokens do
amb_bridge_mediators_var = Application.get_env(:block_scout_web, :amb_bridge_mediators)
amb_bridge_mediators = (amb_bridge_mediators_var && String.split(amb_bridge_mediators_var, ",")) || []
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
foreign_json_rpc = Application.get_env(:block_scout_web, :foreign_json_rpc)
eth_call_foreign_json_rpc_named_arguments =
compose_foreign_json_rpc_named_arguments(json_rpc_named_arguments, foreign_json_rpc)
amb_bridge_mediators
|> Enum.each(fn amb_bridge_mediator_hash ->
with {:ok, bridge_contract_hash_resp} <-
get_bridge_contract_hash(amb_bridge_mediator_hash, json_rpc_named_arguments),
bridge_contract_hash <- decode_contract_address_hash_response(bridge_contract_hash_resp),
{:ok, destination_chain_id_resp} <- get_destination_chain_id(bridge_contract_hash, json_rpc_named_arguments),
foreign_chain_id <- decode_contract_integer_response(destination_chain_id_resp),
{:ok, home_token_contract_hash_resp} <-
get_erc677_token_hash(amb_bridge_mediator_hash, json_rpc_named_arguments),
home_token_contract_hash_string <- decode_contract_address_hash_response(home_token_contract_hash_resp),
{:ok, home_token_contract_hash} <- Chain.string_to_address_hash(home_token_contract_hash_string),
{:ok, foreign_mediator_contract_hash_resp} <-
get_foreign_mediator_contract_hash(amb_bridge_mediator_hash, json_rpc_named_arguments),
foreign_mediator_contract_hash <- decode_contract_address_hash_response(foreign_mediator_contract_hash_resp),
{:ok, foreign_token_contract_hash_resp} <-
get_erc677_token_hash(foreign_mediator_contract_hash, eth_call_foreign_json_rpc_named_arguments),
foreign_token_contract_hash_string <-
decode_contract_address_hash_response(foreign_token_contract_hash_resp),
{:ok, foreign_token_contract_hash} <- Chain.string_to_address_hash(foreign_token_contract_hash_string) do
insert_bridged_token_metadata(home_token_contract_hash, %{
foreign_chain_id: foreign_chain_id,
foreign_token_address_hash: foreign_token_contract_hash,
custom_metadata: nil,
type: "amb"
})
set_token_bridged_status(home_token_contract_hash, true)
else
result ->
Logger.debug([
"failed to fetch metadata for token bridged with AMB mediator #{amb_bridge_mediator_hash}",
inspect(result)
])
end
end)
:ok
end
@doc """
Fetches bridged tokens metadata from OmniBridge.
""" """
def fetch_bridged_tokens_metadata(token_addresses) do def fetch_omni_bridged_tokens_metadata(token_addresses) do
Enum.each(token_addresses, fn token_address_hash -> Enum.each(token_addresses, fn token_address_hash ->
created_from_int_tx_success_query = created_from_int_tx_success_query =
from( from(
@ -3627,7 +3690,7 @@ defmodule Explorer.Chain do
set_token_bridged_status(token_address_hash, false) set_token_bridged_status(token_address_hash, false)
created_from_int_tx && created_from_int_tx_success -> created_from_int_tx && created_from_int_tx_success ->
extract_bridged_token_metadata_wrapper(token_address_hash, created_from_int_tx_success) extract_omni_bridged_token_metadata_wrapper(token_address_hash, created_from_int_tx_success)
true -> true ->
:ok :ok
@ -3637,18 +3700,18 @@ defmodule Explorer.Chain do
:ok :ok
end end
defp extract_bridged_token_metadata_wrapper(token_address_hash, created_from_int_tx_success) do defp extract_omni_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) omni_bridge_mediator = Application.get_env(:block_scout_web, :omni_bridge_mediator)
%{transaction_hash: transaction_hash} = created_from_int_tx_success %{transaction_hash: transaction_hash} = created_from_int_tx_success
if multi_token_bridge_mediator && multi_token_bridge_mediator !== "" do if omni_bridge_mediator && omni_bridge_mediator !== "" do
{:ok, multi_token_bridge_mediator_hash} = Chain.string_to_address_hash(multi_token_bridge_mediator) {:ok, omni_bridge_mediator_hash} = Chain.string_to_address_hash(omni_bridge_mediator)
created_by_amb_mediator_query = created_by_amb_mediator_query =
from( from(
it in InternalTransaction, it in InternalTransaction,
where: it.transaction_hash == ^transaction_hash, where: it.transaction_hash == ^transaction_hash,
where: it.to_address_hash == ^multi_token_bridge_mediator_hash where: it.to_address_hash == ^omni_bridge_mediator_hash
) )
created_by_amb_mediator = created_by_amb_mediator =
@ -3656,10 +3719,10 @@ defmodule Explorer.Chain do
|> Repo.all() |> Repo.all()
if Enum.count(created_by_amb_mediator) > 0 do if Enum.count(created_by_amb_mediator) > 0 do
extract_bridged_token_metadata( extract_omni_bridged_token_metadata(
token_address_hash, token_address_hash,
multi_token_bridge_mediator, omni_bridge_mediator,
multi_token_bridge_mediator_hash omni_bridge_mediator_hash
) )
else else
set_token_bridged_status(token_address_hash, false) set_token_bridged_status(token_address_hash, false)
@ -3667,61 +3730,24 @@ defmodule Explorer.Chain do
end end
end end
defp extract_bridged_token_metadata(token_address_hash, multi_token_bridge_mediator, multi_token_bridge_mediator_hash) do defp extract_omni_bridged_token_metadata(token_address_hash, omni_bridge_mediator, omni_bridge_mediator_hash) do
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) 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, _} <- with {:ok, _} <-
get_token_interfaces_version_signature get_token_interfaces_version_signature(token_address_hash, json_rpc_named_arguments),
|> Contract.eth_call_request(token_address_hash, 1, nil, nil)
|> json_rpc(json_rpc_named_arguments),
{:ok, foreign_token_address_abi_encoded} <- {:ok, foreign_token_address_abi_encoded} <-
foreign_token_address_method get_foreign_token_address(omni_bridge_mediator, token_address_hash, json_rpc_named_arguments),
|> Contract.eth_call_request( {:ok, bridge_contract_hash_resp} <-
multi_token_bridge_mediator, get_bridge_contract_hash(omni_bridge_mediator_hash, json_rpc_named_arguments) do
1, foreign_token_address_hash_string = decode_contract_address_hash_response(foreign_token_address_abi_encoded)
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) {:ok, foreign_token_address_hash} = Chain.string_to_address_hash(foreign_token_address_hash_string)
"0x" <> bridge_contract_no_prefix = bridge_contract multi_token_bridge_hash_string = decode_contract_address_hash_response(bridge_contract_hash_resp)
<<_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} = {:ok, foreign_chain_id_abi_encoded} =
destination_chain_id_signature get_destination_chain_id(multi_token_bridge_hash_string, json_rpc_named_arguments)
|> 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 = decode_contract_integer_response(foreign_chain_id_abi_encoded)
{foreign_chain_id, _} = Integer.parse(foreign_chain_id_abi_encoded_no_prefix, 16)
foreign_json_rpc = Application.get_env(:block_scout_web, :foreign_json_rpc) foreign_json_rpc = Application.get_env(:block_scout_web, :foreign_json_rpc)
@ -3731,38 +3757,135 @@ defmodule Explorer.Chain do
insert_bridged_token_metadata(token_address_hash, %{ insert_bridged_token_metadata(token_address_hash, %{
foreign_chain_id: foreign_chain_id, 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 custom_metadata: custom_metadata,
type: "omni"
}) })
set_token_bridged_status(token_address_hash, true) set_token_bridged_status(token_address_hash, true)
end end
end end
defp get_bridge_contract_hash(mediator_hash, json_rpc_named_arguments) do
# keccak 256 from bridgeContract()
bridge_contract_signature = "0xcd596583"
perform_eth_call_request(bridge_contract_signature, mediator_hash, json_rpc_named_arguments)
end
defp get_erc677_token_hash(mediator_hash, json_rpc_named_arguments) do
# keccak 256 from erc677token()
erc677_token_signature = "0x18d8f9c9"
perform_eth_call_request(erc677_token_signature, mediator_hash, json_rpc_named_arguments)
end
defp get_foreign_mediator_contract_hash(mediator_hash, json_rpc_named_arguments) do
# keccak 256 from mediatorContractOnOtherSide()
mediator_contract_on_other_side_signature = "0x871c0760"
perform_eth_call_request(mediator_contract_on_other_side_signature, mediator_hash, json_rpc_named_arguments)
end
defp get_destination_chain_id(bridge_contract_hash, json_rpc_named_arguments) do
# keccak 256 from destinationChainId()
destination_chain_id_signature = "0xb0750611"
perform_eth_call_request(destination_chain_id_signature, bridge_contract_hash, json_rpc_named_arguments)
end
defp get_token_interfaces_version_signature(token_address_hash, json_rpc_named_arguments) do
# keccak 256 from getTokenInterfacesVersion()
get_token_interfaces_version_signature = "0x859ba28c"
perform_eth_call_request(get_token_interfaces_version_signature, token_address_hash, json_rpc_named_arguments)
end
defp get_foreign_token_address(omni_bridge_mediator, token_address_hash, json_rpc_named_arguments) do
# keccak 256 from foreignTokenAddress(address)
foreign_token_address_signature = "0x47ac7d6a"
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
perform_eth_call_request(foreign_token_address_method, omni_bridge_mediator, json_rpc_named_arguments)
end
defp perform_eth_call_request(method, destination, json_rpc_named_arguments)
when not is_nil(json_rpc_named_arguments) do
method
|> Contract.eth_call_request(destination, 1, nil, nil)
|> json_rpc(json_rpc_named_arguments)
end
defp perform_eth_call_request(_method, _destination, json_rpc_named_arguments)
when is_nil(json_rpc_named_arguments) do
:error
end
def decode_contract_address_hash_response(resp) do
case resp do
"0x000000000000000000000000" <> address ->
"0x" <> address
_ ->
nil
end
end
def decode_contract_integer_response(resp) do
case resp do
"0x" <> integer_encoded ->
{integer_value, _} = Integer.parse(integer_encoded, 16)
integer_value
_ ->
nil
end
end
defp set_token_bridged_status(token_address_hash, status) do defp set_token_bridged_status(token_address_hash, status) do
target_token = Repo.get!(Token, token_address_hash) case Repo.get(Token, token_address_hash) do
%Explorer.Chain.Token{bridged: bridged} = target_token ->
if !bridged do
token = Changeset.change(target_token, bridged: status) token = Changeset.change(target_token, bridged: status)
Repo.update(token) Repo.update(token)
end end
_ ->
:ok
end
end
defp insert_bridged_token_metadata(token_address_hash, %{ defp insert_bridged_token_metadata(token_address_hash, %{
foreign_chain_id: foreign_chain_id, 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 custom_metadata: custom_metadata,
type: type
}) do }) do
target_token = Repo.get(Token, token_address_hash)
if target_token do
{:ok, _} = {:ok, _} =
Repo.insert( Repo.insert(
%BridgedToken{ %BridgedToken{
home_token_contract_address_hash: token_address_hash, home_token_contract_address_hash: token_address_hash,
foreign_chain_id: foreign_chain_id, 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 custom_metadata: custom_metadata,
type: type
}, },
on_conflict: :nothing on_conflict: :nothing
) )
end end
end
# get_bridged_token_custom_metadata function currently gets Balancer token composite tokens with their weights # Fetches custom metadata for bridged tokens from the node.
# Currently, gets Balancer token composite tokens with their weights
# from foreign chain # from foreign chain
defp get_bridged_token_custom_metadata(foreign_token_address_hash, json_rpc_named_arguments, foreign_json_rpc) 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 when not is_nil(foreign_json_rpc) and foreign_json_rpc !== "" do
@ -3823,7 +3946,8 @@ defmodule Explorer.Chain do
nil nil
end end
defp compose_foreign_json_rpc_named_arguments(json_rpc_named_arguments, foreign_json_rpc) do defp compose_foreign_json_rpc_named_arguments(json_rpc_named_arguments, foreign_json_rpc)
when foreign_json_rpc != "" do
{_, eth_call_foreign_json_rpc_named_arguments} = {_, eth_call_foreign_json_rpc_named_arguments} =
Keyword.get_and_update(json_rpc_named_arguments, :transport_options, fn transport_options -> Keyword.get_and_update(json_rpc_named_arguments, :transport_options, fn transport_options ->
{_, updated_transport_options} = {_, updated_transport_options} =
@ -3835,6 +3959,16 @@ defmodule Explorer.Chain do
eth_call_foreign_json_rpc_named_arguments eth_call_foreign_json_rpc_named_arguments
end end
defp compose_foreign_json_rpc_named_arguments(_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)
when is_nil(json_rpc_named_arguments) do
nil
end
defp update_transport_options_set_foreign_json_rpc(transport_options, foreign_json_rpc) do 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 -> Keyword.get_and_update(transport_options, :method_to_url, fn method_to_url ->
{_, updated_method_to_url} = {_, updated_method_to_url} =

@ -15,13 +15,16 @@ defmodule Explorer.Chain.BridgedToken do
* `foreign_token_contract_address_hash` - Foreign token's contract hash * `foreign_token_contract_address_hash` - Foreign token's contract hash
* `home_token_contract_address` - The `t:Address.t/0` of the home token's contract * `home_token_contract_address` - The `t:Address.t/0` of the home token's contract
* `home_token_contract_address_hash` - Home token's contract hash foreign key * `home_token_contract_address_hash` - Home token's contract hash foreign key
* `custom_metadata` - Arbitrary string with custom metadata. For instance, tokens/weights for Balance tokens
* `type` - omni/amb
""" """
@type t :: %BridgedToken{ @type t :: %BridgedToken{
foreign_chain_id: Decimal.t(), foreign_chain_id: Decimal.t(),
foreign_token_contract_address_hash: Hash.Address.t(), foreign_token_contract_address_hash: Hash.Address.t(),
home_token_contract_address: %Ecto.Association.NotLoaded{} | 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() custom_metadata: String.t(),
type: String.t()
} }
@derive {Poison.Encoder, @derive {Poison.Encoder,
@ -45,6 +48,7 @@ defmodule Explorer.Chain.BridgedToken do
field(:foreign_chain_id, :decimal) field(:foreign_chain_id, :decimal)
field(:foreign_token_contract_address_hash, Hash.Address) field(:foreign_token_contract_address_hash, Hash.Address)
field(:custom_metadata, :string) field(:custom_metadata, :string)
field(:type, :string)
belongs_to( belongs_to(
:home_token_contract_address, :home_token_contract_address,
@ -59,7 +63,7 @@ defmodule Explorer.Chain.BridgedToken do
end end
@required_attrs ~w(home_token_contract_address_hash)a @required_attrs ~w(home_token_contract_address_hash)a
@optional_attrs ~w(foreign_chain_id foreign_token_contract_address_hash custom_metadata)a @optional_attrs ~w(foreign_chain_id foreign_token_contract_address_hash custom_metadata type)a
@doc false @doc false
def changeset(%BridgedToken{} = bridged_token, params \\ %{}) do def changeset(%BridgedToken{} = bridged_token, params \\ %{}) do

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

@ -0,0 +1,39 @@
defmodule Indexer.SetAmbBridgedMetadataForTokens do
@moduledoc """
Sets token metadata for bridged tokens from AMB extensions.
"""
use GenServer
require Logger
alias Explorer.Chain
def start_link([init_opts, gen_server_opts]) do
start_link(init_opts, gen_server_opts)
end
def start_link(init_opts, gen_server_opts) do
GenServer.start_link(__MODULE__, init_opts, gen_server_opts)
end
@impl GenServer
def init(_opts) do
send(self(), :process_amb_tokens)
{:ok, %{}}
end
@impl GenServer
def handle_info(:process_amb_tokens, state) do
fetch_amb_bridged_tokens_metadata()
{:noreply, state}
end
defp fetch_amb_bridged_tokens_metadata do
:ok = Chain.process_amb_tokens()
Logger.debug(fn -> "Bridged status fetched for AMB tokens" end)
end
end

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

@ -5,7 +5,7 @@ defmodule Indexer.Supervisor do
use Supervisor use Supervisor
alias Indexer.{Block, PendingOpsCleaner, SetBridgedMetadataForTokens} alias Indexer.{Block, PendingOpsCleaner, SetAmbBridgedMetadataForTokens, SetOmniBridgedMetadataForTokens}
alias Indexer.Block.{Catchup, Realtime} alias Indexer.Block.{Catchup, Realtime}
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
@ -129,15 +129,24 @@ defmodule Indexer.Supervisor do
{PendingOpsCleaner, [[], []]} {PendingOpsCleaner, [[], []]}
] ]
multi_token_bridge_mediator = Application.get_env(:block_scout_web, :multi_token_bridge_mediator) omni_bridge_mediator = Application.get_env(:block_scout_web, :omni_bridge_mediator)
all_fetchers = extended_fetchers =
if multi_token_bridge_mediator && multi_token_bridge_mediator !== "" do if omni_bridge_mediator && omni_bridge_mediator !== "" do
[{SetBridgedMetadataForTokens, [[], []]} | basic_fetchers] [{SetOmniBridgedMetadataForTokens, [[], []]} | basic_fetchers]
else else
basic_fetchers basic_fetchers
end end
amb_bridge_mediators = Application.get_env(:block_scout_web, :amb_bridge_mediators)
all_fetchers =
if amb_bridge_mediators && amb_bridge_mediators !== "" do
[{SetAmbBridgedMetadataForTokens, [[], []]} | extended_fetchers]
else
extended_fetchers
end
Supervisor.init( Supervisor.init(
all_fetchers, all_fetchers,
strategy: :one_for_one strategy: :one_for_one

Loading…
Cancel
Save