Merge branch 'master' into vb-fix-npm-vulnerabilities

pull/2854/head
Victor Baranov 5 years ago committed by GitHub
commit d8574d6a25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 97
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
  3. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  4. 19
      apps/block_scout_web/lib/block_scout_web/etherscan.ex
  5. 6
      apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex
  6. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_token/_tokens.html.eex
  7. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex
  8. 45
      apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex
  9. 8
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  10. 4
      apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
  11. 2
      apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex
  12. 4
      apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex
  13. 8
      apps/block_scout_web/lib/block_scout_web/views/address_token_transfer_view.ex
  14. 2
      apps/block_scout_web/lib/block_scout_web/views/address_view.ex
  15. 1
      apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
  16. 7
      apps/block_scout_web/lib/block_scout_web/web_router.ex
  17. 77
      apps/block_scout_web/priv/gettext/default.pot
  18. 77
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  19. 6
      apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs
  20. 12
      apps/block_scout_web/test/block_scout_web/controllers/address_token_transfer_controller_test.exs
  21. 137
      apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs
  22. 32
      apps/explorer/lib/explorer/chain.ex
  23. 7
      apps/explorer/lib/explorer/chain/token_transfer.ex
  24. 40
      apps/explorer/lib/explorer/chain/transaction.ex
  25. 259
      apps/explorer/test/explorer/chain_test.exs

@ -1,6 +1,7 @@
## Current
### Features
- [#2825](https://github.com/poanetwork/blockscout/pull/2825) - separate token transfers and transactions
- [#2787](https://github.com/poanetwork/blockscout/pull/2787) - async fetching of address counters
- [#2791](https://github.com/poanetwork/blockscout/pull/2791) - add ipc client
- [#2449](https://github.com/poanetwork/blockscout/pull/2449) - add ability to send notification events through postgres notify
@ -8,6 +9,7 @@
### Fixes
- [#2854](https://github.com/poanetwork/blockscout/pull/2854) - Fix all npm vulnerabilities
- [#2851](https://github.com/poanetwork/blockscout/pull/2851) - Fix paths for front assets
- [#2843](https://github.com/poanetwork/blockscout/pull/2843) - fix realtime fetcher small skips feature
- [#2841](https://github.com/poanetwork/blockscout/pull/2841) - LUKSO dashboard height fix
- [#2837](https://github.com/poanetwork/blockscout/pull/2837) - fix txlist ordering issue
@ -101,6 +103,7 @@ fixed menu hovers in dark mode desktop view
- [#2724](https://github.com/poanetwork/blockscout/pull/2724) - fix ci by commenting a line in hackney library
- [#2708](https://github.com/poanetwork/blockscout/pull/2708) - add log index to logs view
- [#2723](https://github.com/poanetwork/blockscout/pull/2723) - get rid of ex_json_schema warnings
- [#2740](https://github.com/poanetwork/blockscout/pull/2740) - add verify contract rpc doc
## 2.0.4-beta

@ -8,7 +8,20 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
alias Phoenix.View
import BlockScoutWeb.Chain,
only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1]
only: [current_filter: 1, next_page_params: 3, paging_options: 1, split_list_by_page: 1]
@transaction_necessity_by_association [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[token_transfers: :token] => :optional,
[token_transfers: :to_address] => :optional,
[token_transfers: :from_address] => :optional,
[token_transfers: :token_contract_address] => :optional,
:block => :required
}
]
def index(
conn,
@ -93,4 +106,86 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
not_found(conn)
end
end
def index(
conn,
%{
"address_id" => address_hash_string,
"type" => "JSON"
} = params
) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
options =
@transaction_necessity_by_association
|> Keyword.merge(paging_options(params))
|> Keyword.merge(current_filter(params))
transactions =
Chain.address_hash_to_token_transfers(
address_hash,
options
)
{transactions_paginated, next_page} = split_list_by_page(transactions)
next_page_path =
case next_page_params(next_page, transactions_paginated, params) do
nil ->
nil
next_page_params ->
address_token_transfers_path(
conn,
:index,
address_hash_string,
Map.delete(next_page_params, "type")
)
end
transfers_json =
Enum.map(transactions_paginated, fn transaction ->
View.render_to_string(
TransactionView,
"_tile.html",
conn: conn,
transaction: transaction,
current_address: address
)
end)
json(conn, %{items: transfers_json, next_page_path: next_page_path})
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
def index(
conn,
%{"address_id" => address_hash_string} = params
) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
render(
conn,
"index.html",
address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
current_path: current_path(conn),
counters_path: address_path(conn, :address_counters, %{"id" => to_string(address_hash)})
)
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
end

@ -19,10 +19,6 @@ defmodule BlockScoutWeb.AddressTransactionController do
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[token_transfers: :token] => :optional,
[token_transfers: :to_address] => :optional,
[token_transfers: :from_address] => :optional,
[token_transfers: :token_contract_address] => :optional,
:block => :required
}
]

@ -1946,7 +1946,24 @@ defmodule BlockScoutWeb.Etherscan do
@contract_verify_action %{
name: "verify",
description: "Verify a contract with its source code and contract creation information.",
description: """
Verify a contract with its source code and contract creation information.
<br/>
<br/>
<p class="api-doc-list-item-text">curl POST example:</p>
<br/>
<div class='tab-content'>
<div class='tab-pane fade show active'>
<div class="tile tile-muted p-1">
<div class="m-2">
curl -d '{"addressHash":"0xd6984e092b51337032cf0300c7291e4839be37e1","compilerVersion":"v0.5.4+commit.9549d8ff",
"contractSourceCode":"pragma solidity ^0.5.4;\n","name":"Test","optimization":false}'
-H "Content-Type: application/json" -X POST "https://blockscout.com/eth/kovan/api?module=contract&action=verify"
</pre>
</div>
</div>
</div>
""",
required_params: [
%{
key: "addressHash",

@ -4,6 +4,12 @@
class: "card-tab #{tab_status("transactions", @conn.request_path)}",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Token Transfers"),
class: "card-tab #{tab_status("token_transfers", @conn.request_path)}",
"data-test": "token_transfers_tab_link",
to: address_token_transfers_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Tokens"),
class: "card-tab #{tab_status("tokens", @conn.request_path)}",

@ -2,7 +2,7 @@
<div class="row justify-content align-items-center">
<div class="col-md-7 d-flex flex-column mt-3 mt-md-0">
<%= link(
to: address_token_transfers_path(@conn, :index, @address.hash, @token.contract_address_hash),
to: address_token_transfers_path(@conn, :index, to_string(@address.hash), to_string(@token.contract_address_hash)),
class: "tile-title-lg",
"data-test": "token_transfers_#{@token.contract_address_hash}"
) do %>

@ -11,7 +11,7 @@
data-token-symbol="<%= token_balance.token.symbol %>"
>
<%= link(
to: token_path(@conn, :show, token_balance.token.contract_address_hash),
to: token_path(@conn, :show, to_string(token_balance.token.contract_address_hash)),
class: "dropdown-item"
) do %>
<div class="row">

@ -5,9 +5,54 @@
<div class="card">
<%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %>
<div data-async-load data-async-listing="<%= @current_path %>" class="card-body">
<%= if assigns[:token] do %>
<h2 class="card-title">
<span class="text-muted"><%= gettext "Tokens" %></span> / <%= token_name(@token) %>
</h2>
<% end %>
<%= if !assigns[:token] do %>
<div class="clearfix">
<h2 class="card-title float-left"><%= gettext "Transactions" %></h2>
<div class="dropdown float-right u-push-sm">
<button data-test="filter_dropdown" class="btn-dropdown-line dropdown-toggle" type="button"
id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter: <%= format_current_filter(@filter) %>
</button>
<div class="dropdown-menu dropdown-menu-right filter" aria-labelledby="dropdownMenu2">
<%= link(
gettext("All"),
to: address_token_transfers_path(@conn, :index, to_string(@address.hash)),
class: "address__link address__link--active dropdown-item",
"data-test": "filter_option"
) %>
<%= link(
gettext("To"),
to: address_token_transfers_path(
@conn,
:index,
to_string(@address.hash),
filter: "to"
),
class: "address__link address__link--active dropdown-item",
"data-test": "filter_option"
) %>
<%= link(
gettext("From"),
to: address_token_transfers_path(
@conn,
:index,
to_string(@address.hash),
filter: "from"
),
class: "address__link address__link--active dropdown-item",
"data-test": "filter_option"
) %>
</div>
</div>
</div>
<% end %>
<%= 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 %>

@ -1,7 +1,7 @@
<link rel="preload" href="/css/awesomplete.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/awesomplete.css"></noscript>
<script src="/js/awesomplete.min.js"></script>
<script src="/js/awesomplete-util.min.js"></script>
<link rel="preload" href="<%= static_path(@conn, "/css/awesomplete.css") %>" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="<%= static_path(@conn, "/css/awesomplete.css") %>"></noscript>
<script src="<%= static_path(@conn, "/js/awesomplete.min.js") %>"></script>
<script src="<%= static_path(@conn, "/js/awesomplete-util.min.js") %>"></script>
<nav class="navbar navbar-dark navbar-expand-lg navbar-primary" data-selector="navbar" id="top-navbar">
<script>
if (localStorage.getItem("current-color-mode") === "dark") {

@ -5,8 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
<link rel="preload" href="/css/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/non-critical.css"></noscript>
<link rel="preload" href="<%= static_path(@conn, "/css/non-critical.css") %>" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="<%= static_path(@conn, "/css/non-critical.css") %>"></noscript>
<link rel="apple-touch-icon" sizes="180x180" href="<%= static_path(@conn, "/apple-touch-icon.png") %>">
<link rel="icon" type="image/png" sizes="32x32" href="<%= static_path(@conn, "/favicon-32x32.png") %>">

@ -10,7 +10,7 @@
<span class="d-flex flex-md-row flex-column mt-3 mt-md-0">
<span class="mr-1"><%= gettext "Token ID" %>:</span>
<span class="tile-title">
<%= link(@token_transfer.token_id, to: token_instance_path(@conn, :show, @token.contract_address_hash, to_string(@token_transfer.token_id))) %>
<%= link(@token_transfer.token_id, to: token_instance_path(@conn, :show, "#{@token.contract_address_hash}", "#{@token_transfer.token_id}")) %>
</span>
</span>

@ -8,7 +8,7 @@
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @token_transfer.transaction_hash %>
<span class="text-nowrap">
<%= link to: address_token_transfers_path(@conn, :index, @token_transfer.from_address, @token.contract_address_hash), "data-test": "address_hash_link" do %>
<%= link to: address_token_transfers_path(@conn, :index, to_string(@token_transfer.from_address), to_string(@token.contract_address_hash)), "data-test": "address_hash_link" do %>
<%= render(
BlockScoutWeb.AddressView,
"_responsive_hash.html",
@ -18,7 +18,7 @@
) %>
<% end %>
&rarr;
<%= link to: address_token_transfers_path(@conn, :index, @token_transfer.to_address, @token.contract_address_hash), "data-test": "address_hash_link" do %>
<%= link to: address_token_transfers_path(@conn, :index, to_string(@token_transfer.to_address), to_string(@token.contract_address_hash)), "data-test": "address_hash_link" do %>
<%= render(
BlockScoutWeb.AddressView,
"_responsive_hash.html",

@ -1,3 +1,11 @@
defmodule BlockScoutWeb.AddressTokenTransferView do
use BlockScoutWeb, :view
def format_current_filter(filter) do
case filter do
"to" -> gettext("To")
"from" -> gettext("From")
_ -> gettext("All")
end
end
end

@ -16,6 +16,7 @@ defmodule BlockScoutWeb.AddressView do
"contracts",
"decompiled_contracts",
"internal_transactions",
"token_transfers",
"read_contract",
"tokens",
"transactions",
@ -304,6 +305,7 @@ defmodule BlockScoutWeb.AddressView do
defp tab_name(["tokens"]), do: gettext("Tokens")
defp tab_name(["transactions"]), do: gettext("Transactions")
defp tab_name(["internal_transactions"]), do: gettext("Internal Transactions")
defp tab_name(["token_transfers"]), do: gettext("Token Transfers")
defp tab_name(["contracts"]), do: gettext("Code")
defp tab_name(["decompiled_contracts"]), do: gettext("Decompiled Code")
defp tab_name(["read_contract"]), do: gettext("Read Contract")

@ -230,6 +230,7 @@ defmodule BlockScoutWeb.TransactionView do
def involves_token_transfers?(%Transaction{token_transfers: []}), do: false
def involves_token_transfers?(%Transaction{token_transfers: transfers}) when is_list(transfers), do: true
def involves_token_transfers?(_), do: false
def qr_code(%Transaction{hash: hash}) do
hash

@ -119,6 +119,13 @@ defmodule BlockScoutWeb.WebRouter do
as: :read_contract
)
resources(
"/token_transfers",
AddressTokenTransferController,
only: [:index],
as: :token_transfers
)
resources("/tokens", AddressTokenController, only: [:index], as: :token) do
resources(
"/token_transfers",

@ -124,7 +124,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
#: lib/block_scout_web/views/address_view.ex:99
#: lib/block_scout_web/views/address_view.ex:100
msgid "Address"
msgstr ""
@ -135,9 +135,11 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:27
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:25
#: lib/block_scout_web/templates/address_transaction/index.html.eex:23
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:21
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_token_transfer_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All"
msgstr ""
@ -336,14 +338,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/views/address_view.ex:97
#: lib/block_scout_web/views/address_view.ex:98
msgid "Contract Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:16
#: lib/block_scout_web/views/address_view.ex:37
#: lib/block_scout_web/views/address_view.ex:71
#: lib/block_scout_web/views/address_view.ex:38
#: lib/block_scout_web/views/address_view.ex:72
msgid "Contract Address Pending"
msgstr ""
@ -353,12 +355,12 @@ msgid "Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:261
#: lib/block_scout_web/views/transaction_view.ex:262
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:260
#: lib/block_scout_web/views/transaction_view.ex:261
msgid "Contract Creation"
msgstr ""
@ -497,7 +499,7 @@ msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:50
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
msgid "Decompiled code"
msgstr ""
@ -706,8 +708,10 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:44
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:42
#: lib/block_scout_web/templates/address_transaction/index.html.eex:40
#: lib/block_scout_web/views/address_internal_transaction_view.ex:7
#: lib/block_scout_web/views/address_token_transfer_view.ex:7
#: lib/block_scout_web/views/address_transaction_view.ex:7
msgid "From"
msgstr ""
@ -810,7 +814,7 @@ msgid "There are no logs for this transaction."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:15
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:60
msgid "There are no token transfers for this address."
msgstr ""
@ -847,8 +851,10 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:33
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31
#: lib/block_scout_web/templates/address_transaction/index.html.eex:29
#: lib/block_scout_web/views/address_internal_transaction_view.ex:6
#: lib/block_scout_web/views/address_token_transfer_view.ex:6
#: lib/block_scout_web/views/address_transaction_view.ex:6
msgid "To"
msgstr ""
@ -879,20 +885,22 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:5
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:259
#: lib/block_scout_web/views/transaction_view.ex:260
msgid "Token Transfer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:3
#: lib/block_scout_web/templates/tokens/instance/transfer/index.html.eex:16
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:3
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/tokens/instance/overview_view.ex:71
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:313
#: lib/block_scout_web/views/transaction_view.ex:314
msgid "Token Transfers"
msgstr ""
@ -908,7 +916,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
#: lib/block_scout_web/views/transaction_view.ex:262
#: lib/block_scout_web/views/transaction_view.ex:263
msgid "Transaction"
msgstr ""
@ -1027,8 +1035,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:31
#: lib/block_scout_web/templates/layout/app.html.eex:60
#: lib/block_scout_web/views/address_view.ex:125
#: lib/block_scout_web/views/address_view.ex:125
#: lib/block_scout_web/views/address_view.ex:126
#: lib/block_scout_web/views/address_view.ex:126
msgid "Market Cap"
msgstr ""
@ -1193,7 +1201,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
#: lib/block_scout_web/views/transaction_view.ex:316
#: lib/block_scout_web/views/transaction_view.ex:317
msgid "Raw Trace"
msgstr ""
@ -1300,7 +1308,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61
#: lib/block_scout_web/templates/address_logs/index.html.eex:21
#: lib/block_scout_web/templates/address_token/index.html.eex:13
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:20
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:65
#: lib/block_scout_web/templates/address_transaction/index.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:22
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23
@ -1788,76 +1796,77 @@ msgid "Copy Txn Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:31
#: lib/block_scout_web/templates/address/_tabs.html.eex:37
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/address_view.ex:313
msgid "Blocks Validated"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:40
#: lib/block_scout_web/templates/address/_tabs.html.eex:46
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:165
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/address_view.ex:309
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/views/address_view.ex:310
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
#: lib/block_scout_web/views/address_view.ex:312
msgid "Coin Balance History"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/address_view.ex:310
msgid "Decompiled Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/transaction_view.ex:314
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/transaction_view.ex:315
msgid "Internal Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/transaction_view.ex:315
#: lib/block_scout_web/views/address_view.ex:314
#: lib/block_scout_web/views/transaction_view.ex:316
msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
#: lib/block_scout_web/templates/address/_tabs.html.eex:62
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
#: lib/block_scout_web/views/address_view.ex:309
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: 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:9
#: lib/block_scout_web/views/address_view.ex:304
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
#: lib/block_scout_web/views/address_view.ex:305
msgid "Tokens"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:3
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:17
#: lib/block_scout_web/templates/address_transaction/index.html.eex:15
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50
#: lib/block_scout_web/views/address_view.ex:305
#: lib/block_scout_web/views/address_view.ex:306
msgid "Transactions"
msgstr ""

@ -124,7 +124,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
#: lib/block_scout_web/views/address_view.ex:99
#: lib/block_scout_web/views/address_view.ex:100
msgid "Address"
msgstr ""
@ -135,9 +135,11 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:27
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:25
#: lib/block_scout_web/templates/address_transaction/index.html.eex:23
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:21
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_token_transfer_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All"
msgstr ""
@ -336,14 +338,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/views/address_view.ex:97
#: lib/block_scout_web/views/address_view.ex:98
msgid "Contract Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:16
#: lib/block_scout_web/views/address_view.ex:37
#: lib/block_scout_web/views/address_view.ex:71
#: lib/block_scout_web/views/address_view.ex:38
#: lib/block_scout_web/views/address_view.ex:72
msgid "Contract Address Pending"
msgstr ""
@ -353,12 +355,12 @@ msgid "Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:261
#: lib/block_scout_web/views/transaction_view.ex:262
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:260
#: lib/block_scout_web/views/transaction_view.ex:261
msgid "Contract Creation"
msgstr ""
@ -497,7 +499,7 @@ msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:50
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
msgid "Decompiled code"
msgstr ""
@ -706,8 +708,10 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:44
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:42
#: lib/block_scout_web/templates/address_transaction/index.html.eex:40
#: lib/block_scout_web/views/address_internal_transaction_view.ex:7
#: lib/block_scout_web/views/address_token_transfer_view.ex:7
#: lib/block_scout_web/views/address_transaction_view.ex:7
msgid "From"
msgstr ""
@ -810,7 +814,7 @@ msgid "There are no logs for this transaction."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:15
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:60
msgid "There are no token transfers for this address."
msgstr ""
@ -847,8 +851,10 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:33
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31
#: lib/block_scout_web/templates/address_transaction/index.html.eex:29
#: lib/block_scout_web/views/address_internal_transaction_view.ex:6
#: lib/block_scout_web/views/address_token_transfer_view.ex:6
#: lib/block_scout_web/views/address_transaction_view.ex:6
msgid "To"
msgstr ""
@ -879,20 +885,22 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:5
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:259
#: lib/block_scout_web/views/transaction_view.ex:260
msgid "Token Transfer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:3
#: lib/block_scout_web/templates/tokens/instance/transfer/index.html.eex:16
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:3
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/tokens/instance/overview_view.ex:71
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:313
#: lib/block_scout_web/views/transaction_view.ex:314
msgid "Token Transfers"
msgstr ""
@ -908,7 +916,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
#: lib/block_scout_web/views/transaction_view.ex:262
#: lib/block_scout_web/views/transaction_view.ex:263
msgid "Transaction"
msgstr ""
@ -1027,8 +1035,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:31
#: lib/block_scout_web/templates/layout/app.html.eex:60
#: lib/block_scout_web/views/address_view.ex:125
#: lib/block_scout_web/views/address_view.ex:125
#: lib/block_scout_web/views/address_view.ex:126
#: lib/block_scout_web/views/address_view.ex:126
msgid "Market Cap"
msgstr ""
@ -1193,7 +1201,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
#: lib/block_scout_web/views/transaction_view.ex:316
#: lib/block_scout_web/views/transaction_view.ex:317
msgid "Raw Trace"
msgstr ""
@ -1300,7 +1308,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61
#: lib/block_scout_web/templates/address_logs/index.html.eex:21
#: lib/block_scout_web/templates/address_token/index.html.eex:13
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:20
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:65
#: lib/block_scout_web/templates/address_transaction/index.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:22
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23
@ -1788,76 +1796,77 @@ msgid "Copy Txn Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:31
#: lib/block_scout_web/templates/address/_tabs.html.eex:37
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/address_view.ex:313
msgid "Blocks Validated"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:40
#: lib/block_scout_web/templates/address/_tabs.html.eex:46
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:165
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/address_view.ex:309
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/views/address_view.ex:310
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
#: lib/block_scout_web/views/address_view.ex:312
msgid "Coin Balance History"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/address_view.ex:310
msgid "Decompiled Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/transaction_view.ex:314
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/transaction_view.ex:315
msgid "Internal Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/transaction_view.ex:315
#: lib/block_scout_web/views/address_view.ex:314
#: lib/block_scout_web/views/transaction_view.ex:316
msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
#: lib/block_scout_web/templates/address/_tabs.html.eex:62
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
#: lib/block_scout_web/views/address_view.ex:309
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: 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:9
#: lib/block_scout_web/views/address_view.ex:304
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
#: lib/block_scout_web/views/address_view.ex:305
msgid "Tokens"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:3
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:17
#: lib/block_scout_web/templates/address_transaction/index.html.eex:15
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50
#: lib/block_scout_web/views/address_view.ex:305
#: lib/block_scout_web/views/address_view.ex:306
msgid "Transactions"
msgstr ""

@ -57,7 +57,7 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
to_address: address
)
conn = get(conn, address_token_path(conn, :index, address), type: "JSON")
conn = get(conn, address_token_path(conn, :index, to_string(address.hash)), type: "JSON")
{:ok, %{"items" => items}} =
conn.resp_body
@ -99,7 +99,7 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
%Token{name: name, type: type, inserted_at: inserted_at} = token
conn =
get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), %{
get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, to_string(address.hash)), %{
"token_name" => name,
"token_type" => type,
"token_inserted_at" => inserted_at,
@ -131,7 +131,7 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
insert(:token_transfer, token_contract_address: token.contract_address, from_address: address)
end)
conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), type: "JSON")
conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, to_string(address.hash)), type: "JSON")
{:ok, %{"next_page_path" => next_page_path}} =
conn.resp_body

@ -25,7 +25,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
test "with an address that doesn't exist in our database", %{conn: conn} do
address_hash = "0x8bf38d4764929064f2d4d3a56520a76ab3df415b"
%Token{contract_address_hash: token_hash} = insert(:token)
conn = get(conn, address_token_transfers_path(conn, :index, address_hash, token_hash))
conn = get(conn, address_token_transfers_path(conn, :index, to_string(address_hash), to_string(token_hash)))
assert html_response(conn, 404)
end
@ -45,7 +45,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
%Token{contract_address_hash: token_hash} = insert(:token)
conn =
get(conn, address_token_transfers_path(conn, :index, address_hash, token_hash), %{
get(conn, address_token_transfers_path(conn, :index, to_string(address_hash), to_string(token_hash)), %{
type: "JSON"
})
@ -78,7 +78,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
conn =
get(
conn,
address_token_transfers_path(conn, :index, address.hash, token.contract_address_hash),
address_token_transfers_path(conn, :index, to_string(address.hash), to_string(token.contract_address_hash)),
%{type: "JSON"}
)
@ -122,7 +122,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
conn =
get(
conn,
address_token_transfers_path(conn, :index, address.hash, token.contract_address_hash),
address_token_transfers_path(conn, :index, to_string(address.hash), to_string(token.contract_address_hash)),
%{type: "JSON"}
)
@ -173,7 +173,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
conn =
get(
conn,
address_token_transfers_path(conn, :index, address.hash, token.contract_address_hash),
address_token_transfers_path(conn, :index, to_string(address.hash), to_string(token.contract_address_hash)),
%{type: "JSON"}
)
@ -213,7 +213,7 @@ defmodule BlockScoutWeb.AddressTokenTransferControllerTest do
%Token{contract_address_hash: token_hash} = insert(:token)
conn =
get(conn, address_token_transfers_path(conn, :index, address_hash, token_hash), %{
get(conn, address_token_transfers_path(conn, :index, to_string(address_hash), to_string(token_hash)), %{
type: "JSON"
})

@ -262,143 +262,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
end
end
describe "viewing token transfers" do
test "contributor can see all token transfers that he sent", %{
addresses: addresses,
block: block,
session: session
} do
lincoln = addresses.lincoln
taft = addresses.taft
contract_address = insert(:contract_address)
insert(:token, contract_address: contract_address)
transaction =
:transaction
|> insert(from_address: lincoln, to_address: contract_address)
|> with_block(block)
insert(
:token_transfer,
from_address: lincoln,
to_address: taft,
transaction: transaction,
token_contract_address: contract_address
)
session
|> AddressPage.visit_page(lincoln)
|> assert_has(AddressPage.token_transfers(transaction, count: 1))
|> assert_has(AddressPage.token_transfer(transaction, lincoln, count: 1))
|> assert_has(AddressPage.token_transfer(transaction, taft, count: 1))
|> refute_has(AddressPage.token_transfers_expansion(transaction))
end
test "contributor can see only token transfers related to him", %{
addresses: addresses,
block: block,
session: session
} do
lincoln = addresses.lincoln
taft = addresses.taft
morty = build(:address)
contract_address = insert(:contract_address)
insert(:token, contract_address: contract_address)
transaction =
:transaction
|> insert(from_address: lincoln, to_address: contract_address)
|> with_block(block)
insert(
:token_transfer,
from_address: lincoln,
to_address: taft,
transaction: transaction,
token_contract_address: contract_address
)
insert(
:token_transfer,
from_address: lincoln,
to_address: morty,
transaction: transaction,
token_contract_address: contract_address
)
session
|> AddressPage.visit_page(morty)
|> assert_has(AddressPage.token_transfers(transaction, count: 1))
|> assert_has(AddressPage.token_transfer(transaction, lincoln, count: 1))
|> assert_has(AddressPage.token_transfer(transaction, morty, count: 1))
|> refute_has(AddressPage.token_transfer(transaction, taft, count: 1))
end
test "transactions with multiple token transfers shows only the first one by default", %{
addresses: addresses,
block: block,
session: session
} do
lincoln = addresses.lincoln
taft = addresses.taft
contract_address = insert(:contract_address)
insert(:token, contract_address: contract_address)
transaction =
:transaction
|> insert(from_address: lincoln, to_address: contract_address)
|> with_block(block)
insert_list(
3,
:token_transfer,
from_address: lincoln,
to_address: taft,
transaction: transaction,
token_contract_address: contract_address
)
session
|> AddressPage.visit_page(lincoln)
|> assert_has(AddressPage.token_transfers(transaction, count: 1))
end
test "transaction with multiple token transfers shows all transfers if expanded", %{
addresses: addresses,
block: block,
session: session
} do
lincoln = addresses.lincoln
taft = addresses.taft
contract_address = insert(:contract_address)
insert(:token, contract_address: contract_address)
transaction =
:transaction
|> insert(from_address: lincoln, to_address: contract_address)
|> with_block(block)
insert_list(
3,
:token_transfer,
from_address: lincoln,
to_address: taft,
transaction: transaction,
token_contract_address: contract_address
)
session
|> AddressPage.visit_page(lincoln)
|> click(AddressPage.token_transfers_expansion(transaction))
|> assert_has(AddressPage.token_transfers(transaction, count: 3))
end
end
describe "viewing token transfers from a specific token" do
test "list token transfers related to the address", %{
addresses: addresses,

@ -312,24 +312,10 @@ defmodule Explorer.Chain do
paging_options
|> fetch_transactions()
|> join_associations(necessity_by_association)
|> Transaction.preload_token_transfers(address_hash)
direction_tasks =
base_query
|> Transaction.matching_address_queries_list(direction, address_hash)
|> Enum.map(fn query -> Task.async(fn -> Repo.all(query) end) end)
token_transfers_task =
Task.async(fn ->
transaction_hashes_from_token_transfers =
TokenTransfer.where_any_address_fields_match(direction, address_hash, paging_options)
final_query = where(base_query, [t], t.hash in ^transaction_hashes_from_token_transfers)
Repo.all(final_query)
end)
[token_transfers_task | direction_tasks]
base_query
|> Transaction.matching_address_queries_list(direction, address_hash)
|> Enum.map(fn query -> Task.async(fn -> Repo.all(query) end) end)
end
defp wait_for_address_transactions(tasks) do
@ -349,6 +335,18 @@ defmodule Explorer.Chain do
end)
end
@spec address_hash_to_token_transfers(Hash.Address.t(), Keyword.t()) :: [Transaction.t()]
def address_hash_to_token_transfers(address_hash, options \\ []) do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
direction = Keyword.get(options, :direction)
direction
|> Transaction.transactions_with_token_transfers_direction(address_hash)
|> Transaction.preload_token_transfers(address_hash)
|> handle_paging_options(paging_options)
|> Repo.all()
end
@spec address_to_logs(Hash.Address.t(), Keyword.t()) :: [Log.t()]
def address_to_logs(address_hash, options \\ []) when is_list(options) do
paging_options = Keyword.get(options, :paging_options) || %PagingOptions{page_size: 50}

@ -215,7 +215,8 @@ defmodule Explorer.Chain.TokenTransfer do
from(
tt in TokenTransfer,
where: tt.to_address_hash == ^address_hash,
select: type(tt.transaction_hash, :binary)
select: type(tt.transaction_hash, :binary),
distinct: tt.transaction_hash
)
query
@ -229,7 +230,8 @@ defmodule Explorer.Chain.TokenTransfer do
from(
tt in TokenTransfer,
where: tt.from_address_hash == ^address_hash,
select: type(tt.transaction_hash, :binary)
select: type(tt.transaction_hash, :binary),
distinct: tt.transaction_hash
)
query
@ -249,6 +251,7 @@ defmodule Explorer.Chain.TokenTransfer do
from(token_transfer in TokenTransfer,
where: token_transfer.to_address_hash == ^address_bytes or token_transfer.from_address_hash == ^address_bytes,
select: type(token_transfer.transaction_hash, :binary),
distinct: token_transfer.transaction_hash,
limit: ^page_size
)

@ -598,6 +598,46 @@ defmodule Explorer.Chain.Transaction do
)
end
def transactions_with_token_transfers_direction(direction, address_hash) do
query = transactions_with_token_transfers_query_direction(direction, address_hash)
from(
t in subquery(query),
order_by: [desc: t.block_number, desc: t.index],
preload: [:from_address, :to_address, :created_contract_address, :block]
)
end
defp transactions_with_token_transfers_query_direction(:from, address_hash) do
from(
t in Transaction,
inner_join: tt in TokenTransfer,
on: t.hash == tt.transaction_hash,
where: tt.from_address_hash == ^address_hash,
distinct: :hash
)
end
defp transactions_with_token_transfers_query_direction(:to, address_hash) do
from(
t in Transaction,
inner_join: tt in TokenTransfer,
on: t.hash == tt.transaction_hash,
where: tt.to_address_hash == ^address_hash,
distinct: :hash
)
end
defp transactions_with_token_transfers_query_direction(_, address_hash) do
from(
t in Transaction,
inner_join: tt in TokenTransfer,
on: t.hash == tt.transaction_hash,
where: tt.from_address_hash == ^address_hash or tt.to_address_hash == ^address_hash,
distinct: :hash
)
end
@doc """
Builds an `Ecto.Query` to fetch transactions with the specified block_number
"""

@ -316,7 +316,6 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(from_address: address)
|> with_block()
|> Repo.preload(:token_transfers)
assert [transaction] ==
Chain.address_to_transactions_with_rewards(address_hash, direction: :from)
@ -330,7 +329,6 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(to_address: address)
|> with_block()
|> Repo.preload(:token_transfers)
assert [transaction] ==
Chain.address_to_transactions_with_rewards(address_hash, direction: :to)
@ -344,7 +342,6 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(from_address: address)
|> with_block()
|> Repo.preload(:token_transfers)
# only contains "from" transaction
assert [transaction] ==
@ -359,7 +356,6 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(to_address: address)
|> with_block()
|> Repo.preload(:token_transfers)
assert [transaction] ==
Chain.address_to_transactions_with_rewards(address_hash, direction: :to)
@ -374,13 +370,11 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(to_address: address)
|> with_block(block)
|> Repo.preload(:token_transfers)
transaction2 =
:transaction
|> insert(from_address: address)
|> with_block(block)
|> Repo.preload(:token_transfers)
assert [transaction2, transaction1] ==
Chain.address_to_transactions_with_rewards(address_hash)
@ -424,161 +418,6 @@ defmodule Explorer.ChainTest do
|> Enum.map(& &1.hash)
end
test "returns just the token transfers related to the given address" do
%Address{hash: address_hash} = address = insert(:address)
transaction =
:transaction
|> insert(to_address: address)
|> with_block()
token_transfer =
insert(
:token_transfer,
to_address: address,
transaction: transaction
)
insert(
:token_transfer,
to_address: build(:address),
transaction: transaction
)
transaction =
address_hash
|> Chain.address_to_transactions_with_rewards()
|> List.first()
token_transfers_related =
Enum.map(
transaction.token_transfers,
&{&1.transaction_hash, &1.log_index}
)
assert token_transfers_related == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end
test "returns just the token transfers related to the given contract address" do
contract_address =
insert(
:address,
contract_code: Factory.data("contract_code")
)
transaction =
:transaction
|> insert(to_address: contract_address)
|> with_block()
token_transfer =
insert(
:token_transfer,
to_address: contract_address,
transaction: transaction
)
insert(
:token_transfer,
to_address: build(:address),
transaction: transaction
)
transaction =
contract_address.hash
|> Chain.address_to_transactions_with_rewards()
|> List.first()
token_transfers_contract_address =
Enum.map(
transaction.token_transfers,
&{&1.transaction_hash, &1.log_index}
)
assert token_transfers_contract_address == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end
test "returns all token transfers when the given address is the token contract address" do
%Address{hash: contract_address_hash} =
contract_address = insert(:address, contract_code: Factory.data("contract_code"))
transaction =
:transaction
|> insert(to_address: contract_address)
|> with_block()
insert(
:token_transfer,
to_address: build(:address),
token_contract_address: contract_address,
transaction: transaction
)
insert(
:token_transfer,
to_address: build(:address),
token_contract_address: contract_address,
transaction: transaction
)
transaction = Chain.address_to_transactions_with_rewards(contract_address_hash) |> List.first()
assert Enum.count(transaction.token_transfers) == 2
end
test "returns all transactions that the address is present only in the token transfers" do
john = insert(:address)
paul = insert(:address)
contract_address = insert(:contract_address)
transaction_one =
:transaction
|> insert(
from_address: john,
from_address_hash: john.hash,
to_address: contract_address,
to_address_hash: contract_address.hash
)
|> with_block()
insert(
:token_transfer,
from_address: john,
to_address: paul,
transaction: transaction_one,
amount: 1
)
transaction_two =
:transaction
|> insert(
from_address: john,
from_address_hash: john.hash,
to_address: contract_address,
to_address_hash: contract_address.hash
)
|> with_block()
insert(
:token_transfer,
from_address: john,
to_address: paul,
transaction: transaction_two,
amount: 1
)
transactions_hashes =
paul.hash
|> Chain.address_to_transactions_with_rewards()
|> Enum.map(& &1.hash)
assert Enum.member?(transactions_hashes, transaction_one.hash) == true
assert Enum.member?(transactions_hashes, transaction_two.hash) == true
end
test "with transactions can be paginated" do
%Address{hash: address_hash} = address = insert(:address)
@ -1282,6 +1121,104 @@ defmodule Explorer.ChainTest do
end
end
describe "address_hash_to_token_transfers/2" do
test "returns just the token transfers related to the given contract address" do
contract_address =
insert(
:address,
contract_code: Factory.data("contract_code")
)
transaction =
:transaction
|> insert(to_address: contract_address)
|> with_block()
token_transfer =
insert(
:token_transfer,
to_address: contract_address,
transaction: transaction
)
insert(
:token_transfer,
to_address: build(:address),
transaction: transaction
)
transaction =
contract_address.hash
|> Chain.address_hash_to_token_transfers()
|> List.first()
token_transfers_contract_address =
Enum.map(
transaction.token_transfers,
&{&1.transaction_hash, &1.log_index}
)
assert token_transfers_contract_address == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end
test "returns just the token transfers related to the given address" do
%Address{hash: address_hash} = address = insert(:address)
transaction =
:transaction
|> insert(to_address: address)
|> with_block()
token_transfer =
insert(
:token_transfer,
to_address: address,
transaction: transaction
)
insert(
:token_transfer,
to_address: build(:address),
transaction: transaction
)
transaction =
address_hash
|> Chain.address_hash_to_token_transfers()
|> List.first()
token_transfers_related =
Enum.map(
transaction.token_transfers,
&{&1.transaction_hash, &1.log_index}
)
assert token_transfers_related == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end
test "fetches token transfers by address hash" do
address = insert(:address)
token_transfer =
insert(
:token_transfer,
from_address: address,
amount: 1
)
[transaction_hash] =
address.hash
|> Chain.address_hash_to_token_transfers()
|> Enum.map(& &1.hash)
assert transaction_hash == token_transfer.transaction_hash
end
end
# Full tests in `test/explorer/import_test.exs`
describe "import/1" do
@import_data %{

Loading…
Cancel
Save