Bridged tokens

pull/3227/head
Victor Baranov 4 years ago
parent edf4627f29
commit 089b74aafe
  1. 1
      CHANGELOG.md
  2. 1
      apps/block_scout_web/assets/css/app.scss
  3. 21
      apps/block_scout_web/assets/css/components/_external_link.scss
  4. 15
      apps/block_scout_web/assets/css/components/_navbar.scss
  5. 3
      apps/block_scout_web/config/config.exs
  6. 9
      apps/block_scout_web/lib/block_scout_web/templates/tokens/_tile.html.eex
  7. 3
      apps/block_scout_web/lib/block_scout_web/templates/tokens/index.html.eex
  8. 10
      apps/block_scout_web/lib/block_scout_web/templates/tokens/overview/_details.html.eex
  9. 44
      apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex
  10. 32
      apps/block_scout_web/priv/gettext/default.pot
  11. 32
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  12. 2
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/contract.ex
  13. 171
      apps/explorer/lib/explorer/chain.ex
  14. 62
      apps/explorer/lib/explorer/chain/bridged_token.ex
  15. 4
      apps/explorer/lib/explorer/chain/token.ex
  16. 9
      apps/explorer/priv/repo/migrations/20200806125649_token_add_bridged_column.exs
  17. 20
      apps/explorer/priv/repo/migrations/20200807064700_bridged_tokens_table.exs
  18. 2
      apps/indexer/config/config.exs
  19. 62
      apps/indexer/lib/indexer/set_bridged_status_for_tokens.ex
  20. 3
      apps/indexer/lib/indexer/supervisor.ex

@ -1,6 +1,7 @@
## Current
### Features
- [#3227](https://github.com/poanetwork/blockscout/pull/3227) - Distinguishing of bridged tokens
- [#3224](https://github.com/poanetwork/blockscout/pull/3224) - Top tokens page
### Fixes

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

@ -0,0 +1,21 @@
.external-link-icon {
float: right;
margin-top: -1px;
& {
&.active,
&:hover,
&:focus {
path {
fill: $header-icon-color-hover;
}
}
}
}
.external-token-icon {
path {
fill: $header-icon-color-hover;
}
}

@ -260,18 +260,3 @@ $navbar-logo-width: auto !default;
transition: none !important;
}
}
.external-link-icon {
float: right;
margin-top: -1px;
& {
&.active,
&:hover,
&:focus {
path {
fill: $header-icon-color-hover;
}
}
}
}

@ -34,7 +34,8 @@ config :block_scout_web,
webapp_url: System.get_env("WEBAPP_URL"),
api_url: System.get_env("API_URL"),
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")
config :block_scout_web, BlockScoutWeb.Counters.BlocksIndexedCounter, enabled: true

@ -20,6 +20,15 @@
use_custom_tooltip: false
%>
</td>
<td class="stakes-td">
<%= case @token.bridged do %>
<% nil -> %>
<i style="color: #f7b32b; font-size: 20px;" class="far fa-question-circle"></i>
<% true -> %>
<i style="color: #20b760; font-size: 20px;" class="far fa-check-circle"></i>
<% false -> %>
<% end %>
</td>
<td class="stakes-td">
<%= if decimals?(@token) do %>
<span data-test="token_supply"><%= format_according_to_decimals(@token.total_supply, @token.decimals) %></span>

@ -18,6 +18,9 @@
</th>
<th class="stakes-table-th">
<div class="stakes-table-th-content">Address</div>
</th>
<th class="stakes-table-th">
<div class="stakes-table-th-content">Bridged?</div>
</th>
<th class="stakes-table-th">
<div class="stakes-table-th-content">

@ -42,6 +42,16 @@
</span>
</span>
</span>
<!-- bridged token -->
<%= if @token.bridged do %>
<div style="margin-top: 15px; font-size: 12px;">
<span class="mr-4 mb-3 mb-md-0" style="margin-right: 30px;">
Token is bridged
</span>
<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>
</div>
<% end %>
</h1>
<h3><%= Address.checksum(@token.contract_address_hash) %></h3>

@ -56,4 +56,48 @@ defmodule BlockScoutWeb.Tokens.OverviewView do
price = token.usd_value
Decimal.mult(tokens, price)
end
def foreign_bridged_token_explorer_link(token) do
chain_id = Map.get(token, :foreign_chain_id)
base_token_explorer_link = get_base_token_explorer_link(chain_id)
foreign_token_contract_address_hash_string_no_prefix =
token.foreign_token_contract_address_hash.bytes
|> Base.encode16(case: :lower)
foreign_token_contract_address_hash_string = "0x" <> foreign_token_contract_address_hash_string_no_prefix
base_token_explorer_link <> foreign_token_contract_address_hash_string
end
defp get_base_token_explorer_link(chain_id) when not is_nil(chain_id) do
case Decimal.to_integer(chain_id) do
100 ->
"https://blockscout.com/poa/xdai/tokens/"
99 ->
"https://blockscout.com/poa/core/tokens/"
77 ->
"https://blockscout.com/poa/sokol/tokens/"
42 ->
"https://kovan.etherscan.io/token/"
3 ->
"https://ropsten.etherscan.io/token/"
4 ->
"https://rinkeby.etherscan.io/token/"
5 ->
"https://goerli.etherscan.io/token/"
1 ->
"https://etherscan.io/token/"
end
end
defp get_base_token_explorer_link(_), do: "https://etherscan.io/"
end

@ -107,7 +107,7 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:85
#: lib/block_scout_web/templates/layout/_topnav.html.eex:93
msgid "APIs"
msgstr ""
@ -631,7 +631,7 @@ msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:99
#: lib/block_scout_web/templates/layout/_topnav.html.eex:107
msgid "Eth RPC"
msgstr ""
@ -732,7 +732,7 @@ msgid "Github"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:89
#: lib/block_scout_web/templates/layout/_topnav.html.eex:97
msgid "GraphQL"
msgstr ""
@ -1175,7 +1175,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:94
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:105
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115
msgid "QR Code"
msgstr ""
@ -1185,7 +1185,7 @@ msgid "Query"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:94
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
msgid "RPC"
msgstr ""
@ -1243,14 +1243,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:164
#: lib/block_scout_web/templates/layout/_topnav.html.eex:181
#: lib/block_scout_web/templates/layout/_topnav.html.eex:172
#: lib/block_scout_web/templates/layout/_topnav.html.eex:189
msgid "Search"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:158
#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
#: lib/block_scout_web/templates/layout/_topnav.html.eex:166
#: lib/block_scout_web/templates/layout/_topnav.html.eex:170
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1446,7 +1446,7 @@ msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:75
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:85
msgid "Total Supply"
msgstr ""
@ -1601,7 +1601,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:55
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:65
msgid "View Contract"
msgstr ""
@ -1715,8 +1715,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:142
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:95
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:103
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:114
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:116
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:124
msgid "Close"
msgstr ""
@ -1733,7 +1733,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:69
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:63
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:73
msgid "Decimals"
msgstr ""
@ -1850,6 +1850,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
#: lib/block_scout_web/templates/layout/_topnav.html.eex:83
#: lib/block_scout_web/templates/tokens/index.html.eex:4
#: lib/block_scout_web/views/address_view.ex:341
msgid "Tokens"
msgstr ""
@ -1930,7 +1932,7 @@ msgid "Write Proxy"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
#: lib/block_scout_web/templates/layout/_topnav.html.eex:120
msgid "Apps"
msgstr ""

@ -107,7 +107,7 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:85
#: lib/block_scout_web/templates/layout/_topnav.html.eex:93
msgid "APIs"
msgstr ""
@ -631,7 +631,7 @@ msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:99
#: lib/block_scout_web/templates/layout/_topnav.html.eex:107
msgid "Eth RPC"
msgstr ""
@ -732,7 +732,7 @@ msgid "Github"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:89
#: lib/block_scout_web/templates/layout/_topnav.html.eex:97
msgid "GraphQL"
msgstr ""
@ -1175,7 +1175,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:94
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:105
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115
msgid "QR Code"
msgstr ""
@ -1185,7 +1185,7 @@ msgid "Query"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:94
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
msgid "RPC"
msgstr ""
@ -1243,14 +1243,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:164
#: lib/block_scout_web/templates/layout/_topnav.html.eex:181
#: lib/block_scout_web/templates/layout/_topnav.html.eex:172
#: lib/block_scout_web/templates/layout/_topnav.html.eex:189
msgid "Search"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:158
#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
#: lib/block_scout_web/templates/layout/_topnav.html.eex:166
#: lib/block_scout_web/templates/layout/_topnav.html.eex:170
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1446,7 +1446,7 @@ msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:75
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:85
msgid "Total Supply"
msgstr ""
@ -1601,7 +1601,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:55
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:65
msgid "View Contract"
msgstr ""
@ -1715,8 +1715,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:142
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:95
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:103
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:114
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:116
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:124
msgid "Close"
msgstr ""
@ -1733,7 +1733,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:69
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:63
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:73
msgid "Decimals"
msgstr ""
@ -1850,6 +1850,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
#: lib/block_scout_web/templates/layout/_topnav.html.eex:83
#: lib/block_scout_web/templates/tokens/index.html.eex:4
#: lib/block_scout_web/views/address_view.ex:341
msgid "Tokens"
msgstr ""
@ -1930,7 +1932,7 @@ msgid "Write Proxy"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
#: lib/block_scout_web/templates/layout/_topnav.html.eex:120
msgid "Apps"
msgstr ""

@ -70,7 +70,7 @@ defmodule EthereumJSONRPC.Contract do
Enum.map(requests, fn _ -> format_error(error) end)
end
defp eth_call_request(data, contract_address, id, block_number, from) do
def eth_call_request(data, contract_address, id, block_number, from) do
block =
case block_number do
nil -> "latest"

@ -22,9 +22,9 @@ defmodule Explorer.Chain do
select: 3
]
import EthereumJSONRPC, only: [integer_to_quantity: 1, fetch_block_internal_transactions: 2]
import EthereumJSONRPC, only: [integer_to_quantity: 1, json_rpc: 2, fetch_block_internal_transactions: 2]
alias ABI.TypeDecoder
alias ABI.{TypeDecoder, TypeEncoder}
alias Ecto.Adapters.SQL
alias Ecto.{Changeset, Multi}
@ -42,6 +42,7 @@ defmodule Explorer.Chain do
Address.CurrentTokenBalance,
Address.TokenBalance,
Block,
BridgedToken,
Data,
DecompiledSmartContract,
Hash,
@ -1728,7 +1729,7 @@ defmodule Explorer.Chain do
base_query =
from(t in Token,
where: t.total_supply > ^0,
order_by: [desc: t.holder_count],
order_by: [desc: t.holder_count, asc: t.name],
preload: [:contract_address]
)
@ -3375,6 +3376,151 @@ defmodule Explorer.Chain do
Repo.stream_reduce(query, [], &[&1 | &2])
end
@doc """
Returns a list of token addresses `t:Address.t/0`s that don't have an
bridged property revealed.
"""
def unprocessed_token_addresses_to_reveal_bridged_tokens do
query =
from(t in Token,
where: is_nil(t.bridged),
select: t.contract_address_hash
)
Repo.stream_reduce(query, [], &[&1 | &2])
end
@doc """
Fetches bridges status for tokens.
"""
def fetch_tokens_bridged_status(token_addresses) do
Enum.each(token_addresses, fn token_address_hash ->
created_from_factory_query =
from(
it in InternalTransaction,
where: it.created_contract_address_hash == ^token_address_hash
)
created_from_factory =
created_from_factory_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
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
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)
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)
end
end)
:ok
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)
Repo.update(token)
end
defp set_bridged_token_metadata(token_address_hash, %{
foreign_chain_id: foreign_chain_id,
foreign_token_address_hash: foreign_token_address_hash
}) 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
},
on_conflict: :nothing
)
end
@doc """
Fetches a `t:Token.t/0` by an address hash.
@ -3394,8 +3540,11 @@ defmodule Explorer.Chain do
query =
from(
token in Token,
where: token.contract_address_hash == ^hash
t in Token,
left_join: bt in BridgedToken,
on: t.contract_address_hash == bt.home_token_contract_address_hash,
where: t.contract_address_hash == ^hash,
select: [t, bt]
)
query
@ -3405,8 +3554,16 @@ defmodule Explorer.Chain do
nil ->
{:error, :not_found}
%Token{} = token ->
{:ok, token}
[%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)
extended_token =
token
|> Map.put(:foreign_token_contract_address_hash, foreign_token_contract_address_hash)
|> Map.put(:foreign_chain_id, foreign_chain_id)
{:ok, extended_token}
end
end

@ -0,0 +1,62 @@
defmodule Explorer.Chain.BridgedToken do
@moduledoc """
Represents a bridged token.
"""
use Explorer.Schema
import Ecto.Changeset
alias Explorer.Chain.{BridgedToken, Hash, Token}
@typedoc """
* `foreign_chain_id` - chain ID of a foreign token
* `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_hash` - Home token's contract hash foreign key
"""
@type t :: %BridgedToken{
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()
}
@derive {Poison.Encoder,
except: [
:__meta__,
:home_token_contract_address,
:inserted_at,
:updated_at
]}
@primary_key false
schema "bridged_tokens" do
field(:foreign_chain_id, :decimal)
field(:foreign_token_contract_address_hash, Hash.Address)
belongs_to(
:home_token_contract_address,
Token,
foreign_key: :home_token_contract_address_hash,
primary_key: true,
references: :contract_address_hash,
type: Hash.Address
)
timestamps()
end
@required_attrs ~w(home_token_contract_address_hash)a
@optional_attrs ~w(foreign_chain_id foreign_token_contract_address_hash)a
@doc false
def changeset(%BridgedToken{} = bridged_token, params \\ %{}) do
bridged_token
|> cast(params, @required_attrs ++ @optional_attrs)
|> validate_required(@required_attrs)
|> foreign_key_constraint(:home_token_contract_address)
|> unique_constraint(:home_token_contract_address_hash)
end
end

@ -45,7 +45,8 @@ defmodule Explorer.Chain.Token do
cataloged: boolean(),
contract_address: %Ecto.Association.NotLoaded{} | Address.t(),
contract_address_hash: Hash.Address.t(),
holder_count: non_neg_integer() | nil
holder_count: non_neg_integer() | nil,
bridged: boolean()
}
@derive {Poison.Encoder,
@ -65,6 +66,7 @@ defmodule Explorer.Chain.Token do
field(:type, :string)
field(:cataloged, :boolean)
field(:holder_count, :integer)
field(:bridged, :boolean)
belongs_to(
:contract_address,

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Migrations.TokenAddBridgedColumn do
use Ecto.Migration
def change do
alter table(:tokens) do
add(:bridged, :boolean, null: true)
end
end
end

@ -0,0 +1,20 @@
defmodule Explorer.Repo.Migrations.BridgedTokensTable do
use Ecto.Migration
def change do
create table(:bridged_tokens, primary_key: false) do
add(:foreign_chain_id, :numeric, null: false)
add(:foreign_token_contract_address_hash, :bytea, null: false)
add(
:home_token_contract_address_hash,
references(:tokens, column: :contract_address_hash, on_delete: :delete_all, type: :bytea),
null: false
)
timestamps()
end
create(unique_index(:bridged_tokens, :home_token_contract_address_hash))
end
end

@ -44,6 +44,8 @@ config :indexer, Indexer.Fetcher.PendingTransaction.Supervisor,
# config :indexer, Indexer.Fetcher.ReplacedTransaction.Supervisor, disabled?: true
# config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: true
config :indexer, Indexer.Fetcher.StakingPools.Supervisor, disabled?: true
# System.get_env("MULTI_TOKEN_BRIDGE_MEDIATOR", "") == ""
# config :indexer, Indexer.SetBridgedStatusForTokens.Supervisor, disabled?: true
config :indexer, Indexer.Supervisor, enabled: System.get_env("DISABLE_INDEXER") != "true"

@ -0,0 +1,62 @@
defmodule Indexer.SetBridgedStatusForTokens do
@moduledoc """
Peiodically checks unprocessed tokens and sets bridged status.
"""
use GenServer
require Logger
alias Explorer.Chain
@interval :timer.minutes(1)
# def child_spec([init_arguments]) do
# child_spec([init_arguments, []])
# end
# def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
# default = %{
# id: __MODULE__,
# start: {__MODULE__, :start_link, start_link_arguments}
# }
# Supervisor.child_spec(default, [])
# end
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
interval = opts[:interval] || @interval
Process.send_after(self(), :reveal_unprocessed_tokens, interval)
{:ok, %{interval: interval}}
end
@impl GenServer
def handle_info(:reveal_unprocessed_tokens, %{interval: interval} = state) do
Logger.debug(fn -> "Reveal unprocessed tokens" end)
{:ok, token_addresses} = Chain.unprocessed_token_addresses_to_reveal_bridged_tokens()
fetch_tokens_bridged_status(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)
Logger.debug(fn -> "Bridged status fetched for tokens" end)
end
end

@ -5,7 +5,7 @@ defmodule Indexer.Supervisor do
use Supervisor
alias Indexer.{Block, PendingOpsCleaner}
alias Indexer.{Block, PendingOpsCleaner, SetBridgedStatusForTokens}
alias Indexer.Block.{Catchup, Realtime}
alias Indexer.Fetcher.{
@ -123,6 +123,7 @@ defmodule Indexer.Supervisor do
# Out-of-band fetchers
{CoinBalanceOnDemand.Supervisor, [json_rpc_named_arguments]},
{SetBridgedStatusForTokens, [[], []]},
# Temporary workers
{UncatalogedTokenTransfers.Supervisor, [[]]},

Loading…
Cancel
Save