Show USD values for the POA Values in Transaction Details and Account Details
pull/192/head
Jimmy Lauzau 7 years ago committed by GitHub
commit 67b61f98e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      apps/explorer/lib/explorer.ex
  2. 2
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  3. 7
      apps/explorer/lib/explorer/market/history/source/crypto_compare.ex
  4. 2
      apps/explorer_web/lib/explorer_web.ex
  5. 4
      apps/explorer_web/lib/explorer_web/controllers/address_internal_transaction_controller.ex
  6. 4
      apps/explorer_web/lib/explorer_web/controllers/address_transaction_controller.ex
  7. 6
      apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex
  8. 41
      apps/explorer_web/lib/explorer_web/controllers/transaction_controller.ex
  9. 50
      apps/explorer_web/lib/explorer_web/controllers/transaction_internal_transaction_controller.ex
  10. 6
      apps/explorer_web/lib/explorer_web/controllers/transaction_log_controller.ex
  11. 36
      apps/explorer_web/lib/explorer_web/exchange_rates/usd.ex
  12. 7
      apps/explorer_web/lib/explorer_web/router.ex
  13. 5
      apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
  14. 2
      apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
  15. 2
      apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
  16. 12
      apps/explorer_web/lib/explorer_web/templates/transaction/overview.html.eex
  17. 2
      apps/explorer_web/lib/explorer_web/templates/transaction_internal_transaction/index.html.eex
  18. 18
      apps/explorer_web/lib/explorer_web/views/address_view.ex
  19. 36
      apps/explorer_web/lib/explorer_web/views/currency_helpers.ex
  20. 9
      apps/explorer_web/lib/explorer_web/views/transaction_internal_transaction_view.ex
  21. 42
      apps/explorer_web/lib/explorer_web/views/transaction_view.ex
  22. 69
      apps/explorer_web/priv/gettext/default.pot
  23. 69
      apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
  24. 10
      apps/explorer_web/test/explorer_web/controllers/address_internal_transaction_controller_test.exs
  25. 13
      apps/explorer_web/test/explorer_web/controllers/address_transaction_controller_test.exs
  26. 59
      apps/explorer_web/test/explorer_web/controllers/transaction_controller_test.exs
  27. 62
      apps/explorer_web/test/explorer_web/controllers/transaction_internal_transaction_controller_test.exs
  28. 10
      apps/explorer_web/test/explorer_web/controllers/transaction_log_controller_test.exs
  29. 42
      apps/explorer_web/test/explorer_web/exchange_rates/usd_test.exs
  30. 26
      apps/explorer_web/test/explorer_web/views/address_view_test.exs
  31. 16
      apps/explorer_web/test/explorer_web/views/currency_helpers_test.exs
  32. 37
      apps/explorer_web/test/explorer_web/views/transaction_view_test.exs
  33. 1
      apps/explorer_web/test/support/conn_case.ex
  34. 5
      apps/explorer_web/test/support/factory.ex

@ -6,4 +6,11 @@ defmodule Explorer do
Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others.
"""
@doc """
Returns the configured coin for `Explorer`
"""
def coin do
Application.get_env(:explorer, :coin)
end
end

@ -22,7 +22,7 @@ defmodule Explorer.Chain.InternalTransaction do
* `to_address_hash` - hash of the sink of the `value`
* `trace_address` - list of traces
* `transaction` - transaction in which this transaction occured
* `transaction_id` - foreign key for `transaction`
* `transaction_hash` - foreign key for `transaction`
* `type` - type of internal transaction
* `value` - value of transfered from `from_address` to `to_address`
"""

@ -37,11 +37,6 @@ defmodule Explorer.Market.History.Source.CryptoCompare do
configured_url || "https://min-api.cryptocompare.com"
end
@spec configured_coin :: String.t()
defp configured_coin do
Application.get_env(:explorer, :coin)
end
@spec date(unix_timestamp()) :: Date.t()
defp date(unix_timestamp) do
unix_timestamp
@ -65,7 +60,7 @@ defmodule Explorer.Market.History.Source.CryptoCompare do
@spec history_url(non_neg_integer()) :: String.t()
defp history_url(previous_days) do
query_params = %{
"fsym" => configured_coin(),
"fsym" => Explorer.coin(),
"limit" => previous_days,
"tsym" => "USD"
}

@ -40,7 +40,7 @@ defmodule ExplorerWeb do
# Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML
import ExplorerWeb.{Gettext, Router.Helpers, WeiHelpers}
import ExplorerWeb.{CurrencyHelpers, Gettext, Router.Helpers, WeiHelpers}
import Scrivener.HTML
end
end

@ -7,7 +7,8 @@ defmodule ExplorerWeb.AddressInternalTransactionController do
import ExplorerWeb.AddressController, only: [transaction_count: 1]
alias Explorer.Chain
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def index(conn, %{"address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -30,6 +31,7 @@ defmodule ExplorerWeb.AddressInternalTransactionController do
conn,
"index.html",
address: address,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
page: page,
transaction_count: transaction_count(address)

@ -7,7 +7,8 @@ defmodule ExplorerWeb.AddressTransactionController do
import ExplorerWeb.AddressController, only: [transaction_count: 1]
alias Explorer.Chain
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def index(conn, %{"address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -32,6 +33,7 @@ defmodule ExplorerWeb.AddressTransactionController do
conn,
"index.html",
address: address,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
page: page,
transaction_count: transaction_count(address)

@ -12,7 +12,7 @@ defmodule ExplorerWeb.ChainController do
"show.html",
chain: Statistics.fetch(),
market_history_data: Market.fetch_recent_history(30),
exchange_rate: Market.get_exchange_rate(coin()) || Token.null()
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null()
)
end
@ -29,10 +29,6 @@ defmodule ExplorerWeb.ChainController do
end
end
defp coin do
Application.get_env(:explorer, :coin)
end
defp redirect_search_results(conn, %Address{} = item) do
redirect(conn, to: address_path(conn, :show, Gettext.get_locale(), item))
end

@ -12,38 +12,8 @@ defmodule ExplorerWeb.TransactionController do
end
end
def show(conn, %{"id" => hash_string}) do
with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string),
{:ok, transaction} <-
Chain.hash_to_transaction(
hash,
necessity_by_association: %{
block: :optional,
from_address: :optional,
to_address: :optional,
receipt: :optional
}
) do
internal_transactions =
Chain.transaction_hash_to_internal_transactions(
transaction.hash,
necessity_by_association: %{from_address: :required, to_address: :optional}
)
render(
conn,
"show.html",
internal_transactions: internal_transactions,
max_block_number: max_block_number(),
transaction: transaction
)
else
:error ->
not_found(conn)
{:error, :not_found} ->
not_found(conn)
end
def show(conn, %{"id" => id, "locale" => locale}) do
redirect(conn, to: transaction_internal_transaction_path(conn, :index, locale, id))
end
defp do_index(conn, options \\ []) when is_list(options) do
@ -78,11 +48,4 @@ defmodule ExplorerWeb.TransactionController do
defp last_seen_collated_hash(transactions) do
List.last(transactions).hash
end
defp max_block_number do
case Chain.max_block_number() do
{:ok, number} -> number
{:error, :not_found} -> 0
end
end
end

@ -0,0 +1,50 @@
defmodule ExplorerWeb.TransactionInternalTransactionController do
use ExplorerWeb, :controller
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def index(conn, %{"transaction_id" => hash_string}) do
with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string),
{:ok, transaction} <-
Chain.hash_to_transaction(
hash,
necessity_by_association: %{
block: :optional,
from_address: :optional,
to_address: :optional,
receipt: :optional
}
) do
internal_transactions =
Chain.transaction_hash_to_internal_transactions(
transaction.hash,
necessity_by_association: %{from_address: :required, to_address: :optional}
)
max_block_number = max_block_number()
render(
conn,
"index.html",
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
internal_transactions: internal_transactions,
max_block_number: max_block_number,
transaction: transaction
)
else
:error ->
not_found(conn)
{:error, :not_found} ->
not_found(conn)
end
end
defp max_block_number do
case Chain.max_block_number() do
{:ok, number} -> number
{:error, :not_found} -> 0
end
end
end

@ -1,7 +1,8 @@
defmodule ExplorerWeb.TransactionLogController do
use ExplorerWeb, :controller
alias Explorer.Chain
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def index(conn, %{"transaction_id" => transaction_hash_string} = params) do
with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(transaction_hash_string),
@ -27,7 +28,8 @@ defmodule ExplorerWeb.TransactionLogController do
"index.html",
logs: logs,
max_block_number: max_block_number(),
transaction: transaction
transaction: transaction,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null()
)
else
:error ->

@ -0,0 +1,36 @@
defmodule ExplorerWeb.ExchangeRates.USD do
@moduledoc """
Struct and associated conversion functions for USD currency
"""
@typedoc """
Represents USD currency
* `:value` - value in USD
"""
@type t :: %__MODULE__{
value: Decimal.t() | nil
}
defstruct ~w(value)a
alias Explorer.Chain.Wei
alias Explorer.ExchangeRates.Token
def from(nil, _), do: null()
def from(_, nil), do: null()
def from(%Wei{value: nil}, _), do: null()
def from(_, %Token{usd_value: nil}), do: null()
def from(%Wei{} = wei, %Token{usd_value: exchange_rate}) do
ether = Wei.to(wei, :ether)
%__MODULE__{value: Decimal.mult(ether, exchange_rate)}
end
def null do
%__MODULE__{value: nil}
end
end

@ -40,6 +40,13 @@ defmodule ExplorerWeb.Router do
resources("/pending_transactions", PendingTransactionController, only: [:index])
resources "/transactions", TransactionController, only: [:index, :show] do
resources(
"/internal_transactions",
TransactionInternalTransactionController,
only: [:index],
as: :internal_transaction
)
resources("/logs", TransactionLogController, only: [:index], as: :log)
end

@ -7,8 +7,9 @@
<dl>
<div class="address__item">
<dt class="address__item-key"><%= gettext "Balance" %></dt>
<dd class="address__item-value address__balance" title="<%= @address %>" data-test="address_balance">
<%= balance(@address) %>
<dd class="address__item-value address__balance u-text-right" title="<%= @address %>" data-test="address_balance">
<div><%= balance(@address) %> </div>
<div><%= formatted_usd(@address, @exchange_rate) %> </div>
</dd>
</div>
<div class="address__item">

@ -97,7 +97,7 @@
<%= render ExplorerWeb.AddressView, "_link.html", conn: @conn, address: transaction.to_address %>
</td>
<td><%= ExplorerWeb.TransactionView.value(transaction, include_label: false) %></td>
<td><%= ExplorerWeb.TransactionView.fee(transaction) %></td>
<td><%= ExplorerWeb.TransactionView.formatted_fee(transaction, denomination: :ether) %></td>
</tr>
<% end %>
</tbody>

@ -100,7 +100,7 @@
</tr>
<tr>
<th scope="Nonce">
<%= gettext "Gas Limit" %>
<%= gettext "Nonce" %>
</th>
<td>
<%= @block.nonce %>

@ -43,7 +43,8 @@
<%= gettext "Value" %>
</th>
<td>
<%= value(@transaction) %>
<div><%= value(@transaction) %> </div>
<div><%= formatted_usd_value(@transaction, @exchange_rate) %></div>
</td>
</tr>
<tr>
@ -127,6 +128,15 @@
(<%= gas_price(@transaction, :gwei) %>)
</td>
</tr>
<tr>
<th scope="row">
<%= gettext "TX Fee" %>
</th>
<td>
<div><%= formatted_fee(@transaction, denomination: :ether) %></div>
<div><%= formatted_fee(@transaction, exchange_rate: @exchange_rate) %></div>
</td>
</tr>
<tr>
<th scope="row">
<%= gettext "Total Gas Used" %>

@ -1,5 +1,5 @@
<section class="container__section">
<%= render "overview.html", assigns %>
<%= render ExplorerWeb.TransactionView, "overview.html", assigns %>
<div>
<ul class="nav nav-tabs">
<li class="nav-item">

@ -1,7 +1,9 @@
defmodule ExplorerWeb.AddressView do
use ExplorerWeb, :view
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Wei}
alias Explorer.ExchangeRates.Token
alias ExplorerWeb.ExchangeRates.USD
@dialyzer :no_match
@ -14,6 +16,20 @@ defmodule ExplorerWeb.AddressView do
format_wei_value(balance, :ether, fractional_digits: 18)
end
def formatted_usd(%Address{fetched_balance: nil}, _), do: nil
def formatted_usd(%Address{fetched_balance: balance}, %Token{} = exchange_rate) do
case Wei.cast(balance) do
{:ok, wei} ->
wei
|> USD.from(exchange_rate)
|> format_usd_value()
_ ->
nil
end
end
def hash(%Address{hash: hash}) do
to_string(hash)
end

@ -0,0 +1,36 @@
defmodule ExplorerWeb.CurrencyHelpers do
@moduledoc """
Helper functions for interacting with `t:ExplorerWeb.ExchangeRates.USD.t/0` values.
"""
import ExplorerWeb.Gettext
alias ExplorerWeb.ExchangeRates.USD
alias Cldr.Number
@doc """
Formats a `ExplorerWeb.ExchangeRates.USD` value into USD and applies a unit label.
## Examples
iex> format_usd_value(%USD{value: Decimal.new(5)})
"$5 USD"
iex> format_usd_value(%USD{value: Decimal.new(5000)})
"$5,000 USD"
iex> format_usd_value(%USD{value: Decimal.new(0.000005)})
"$0.000005 USD"
"""
@spec format_usd_value(USD.t() | nil) :: binary() | nil
def format_usd_value(nil), do: nil
def format_usd_value(%USD{value: nil}), do: nil
def format_usd_value(%USD{value: value}) do
case Number.to_string(value, format: "#,##0.##################") do
{:ok, formatted} -> "$#{formatted} " <> gettext("USD")
_ -> nil
end
end
end

@ -0,0 +1,9 @@
defmodule ExplorerWeb.TransactionInternalTransactionView do
use ExplorerWeb, :view
@dialyzer :no_match
alias ExplorerWeb.TransactionView
defdelegate value(txn, opts), to: TransactionView
defdelegate gas(txn), to: TransactionView
end

@ -4,7 +4,9 @@ defmodule ExplorerWeb.TransactionView do
alias Cldr.Number
alias Explorer.Chain
alias Explorer.Chain.{Block, InternalTransaction, Transaction, Wei}
alias Explorer.ExchangeRates.Token
alias ExplorerWeb.BlockView
alias ExplorerWeb.ExchangeRates.USD
def confirmations(%Transaction{block: block}, named_arguments) when is_list(named_arguments) do
case block do
@ -20,19 +22,31 @@ defmodule ExplorerWeb.TransactionView do
end
end
@doc """
Calculates the transaction fee and returns a formatted display value.
"""
def fee(%Transaction{} = transaction) do
case Chain.fee(transaction, :wei) do
{:actual, actual} ->
format_wei_value(Wei.from(actual, :wei), :ether, fractional_digits: 18)
{:maximum, maximum} ->
"<= " <> format_wei_value(Wei.from(maximum, :wei), :ether, fractional_digits: 18)
def formatted_fee(%Transaction{} = transaction, opts) do
transaction
|> Chain.fee(:wei)
|> fee_to_currency(opts)
|> case do
{_, nil} -> nil
{:actual, value} -> value
{:maximum, value} -> "<= " <> value
end
end
defp fee_to_currency({fee_type, fee}, denomination: denomination) do
{fee_type, format_wei_value(Wei.from(fee, :wei), denomination, fractional_digits: 18)}
end
defp fee_to_currency({fee_type, fee}, exchange_rate: %Token{} = exchange_rate) do
formatted =
fee
|> Wei.from(:wei)
|> USD.from(exchange_rate)
|> format_usd_value()
{fee_type, formatted}
end
def first_seen(%Transaction{inserted_at: inserted_at}) do
Timex.from_now(inserted_at)
end
@ -41,6 +55,12 @@ defmodule ExplorerWeb.TransactionView do
Number.to_string!(gas)
end
def formatted_usd_value(%Transaction{value: nil}, _token), do: nil
def formatted_usd_value(%Transaction{value: value}, token) do
format_usd_value(USD.from(value, token))
end
def formatted_age(%Transaction{block: block}) do
case block do
nil -> gettext("Pending")
@ -96,7 +116,7 @@ defmodule ExplorerWeb.TransactionView do
## Options
* `:include_label` - Boolean. Defaults to true. Flag for displaying unit with value.
* `:include_label` - Boolean. Defaults to true. Flag for displaying unit with value.
"""
def value(%mod{value: value}, opts \\ []) when is_transaction_type(mod) do
include_label? = Keyword.get(opts, :include_label, true)

@ -66,7 +66,7 @@ msgstr ""
#: lib/explorer_web/templates/pending_transaction/index.html.eex:40
#: lib/explorer_web/templates/transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/overview.html.eex:43
#: lib/explorer_web/templates/transaction/show.html.eex:30
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:30
msgid "Value"
msgstr ""
@ -80,9 +80,8 @@ msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:23
#: lib/explorer_web/templates/block_transaction/index.html.eex:95
#: lib/explorer_web/templates/block_transaction/index.html.eex:103
#: lib/explorer_web/templates/transaction/overview.html.eex:115
#: lib/explorer_web/templates/transaction/show.html.eex:31
#: lib/explorer_web/templates/transaction/overview.html.eex:116
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
msgid "Gas Limit"
msgstr ""
@ -90,7 +89,8 @@ msgstr ""
msgid "Miner"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:83
#: lib/explorer_web/templates/block_transaction/index.html.eex:103
#: lib/explorer_web/templates/transaction/overview.html.eex:84
msgid "Nonce"
msgstr ""
@ -129,17 +129,17 @@ msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:22
#: lib/explorer_web/templates/block/index.html.eex:23
#: lib/explorer_web/templates/chain/_blocks.html.eex:11
#: lib/explorer_web/templates/transaction/overview.html.eex:118
#: lib/explorer_web/templates/transaction/show.html.eex:31
#: lib/explorer_web/templates/transaction/overview.html.eex:119
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
msgid "Gas"
msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:24
#: lib/explorer_web/templates/transaction/overview.html.eex:123
#: lib/explorer_web/templates/transaction/overview.html.eex:124
msgid "Gas Price"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:140
#: lib/explorer_web/templates/transaction/overview.html.eex:150
msgid "Input"
msgstr ""
@ -164,8 +164,8 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:9
#: lib/explorer_web/templates/pending_transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/index.html.eex:36
#: lib/explorer_web/templates/transaction/overview.html.eex:51
#: lib/explorer_web/templates/transaction/show.html.eex:28
#: lib/explorer_web/templates/transaction/overview.html.eex:52
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:28
#: lib/explorer_web/views/address_internal_transaction_view.ex:7
#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "From"
@ -176,7 +176,7 @@ msgstr ""
msgid "Overview"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:90
#: lib/explorer_web/views/transaction_view.ex:110
msgid "Success"
msgstr ""
@ -188,8 +188,8 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:10
#: lib/explorer_web/templates/pending_transaction/index.html.eex:39
#: lib/explorer_web/templates/transaction/index.html.eex:37
#: lib/explorer_web/templates/transaction/overview.html.eex:67
#: lib/explorer_web/templates/transaction/show.html.eex:29
#: lib/explorer_web/templates/transaction/overview.html.eex:68
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:29
#: lib/explorer_web/views/address_internal_transaction_view.ex:6
#: lib/explorer_web/views/address_transaction_view.ex:8
msgid "To"
@ -234,25 +234,25 @@ msgstr ""
#: lib/explorer_web/templates/layout/_topnav.html.eex:33
#: lib/explorer_web/templates/pending_transaction/index.html.eex:21
#: lib/explorer_web/templates/transaction/index.html.eex:19
#: lib/explorer_web/templates/transaction/overview.html.eex:61
#: lib/explorer_web/templates/transaction/overview.html.eex:77
#: lib/explorer_web/views/transaction_view.ex:18
#: lib/explorer_web/views/transaction_view.ex:46
#: lib/explorer_web/views/transaction_view.ex:53
#: lib/explorer_web/views/transaction_view.ex:89
#: lib/explorer_web/templates/transaction/overview.html.eex:62
#: lib/explorer_web/templates/transaction/overview.html.eex:78
#: lib/explorer_web/views/transaction_view.ex:20
#: lib/explorer_web/views/transaction_view.ex:66
#: lib/explorer_web/views/transaction_view.ex:73
#: lib/explorer_web/views/transaction_view.ex:109
msgid "Pending"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:97
#: lib/explorer_web/templates/transaction/overview.html.eex:98
msgid "First Seen"
msgstr ""
#: lib/explorer_web/templates/pending_transaction/index.html.eex:37
#: lib/explorer_web/templates/transaction/overview.html.eex:106
#: lib/explorer_web/templates/transaction/overview.html.eex:107
msgid "Last Seen"
msgstr ""
#: lib/explorer_web/templates/transaction/show.html.eex:14
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:14
#: lib/explorer_web/templates/transaction_log/index.html.eex:14
msgid "Logs"
msgstr ""
@ -302,11 +302,11 @@ msgstr ""
msgid "Next Page"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:87
#: lib/explorer_web/views/transaction_view.ex:107
msgid "Failed"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:88
#: lib/explorer_web/views/transaction_view.ex:108
msgid "Out of Gas"
msgstr ""
@ -329,7 +329,7 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:11
#: lib/explorer_web/templates/pending_transaction/index.html.eex:40
#: lib/explorer_web/templates/transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/show.html.eex:30
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:30
#: lib/explorer_web/views/wei_helpers.ex:84
msgid "Ether"
msgstr ""
@ -341,7 +341,7 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:14
#: lib/explorer_web/templates/address_transaction/index.html.eex:14
#: lib/explorer_web/templates/transaction/show.html.eex:7
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:7
#: lib/explorer_web/templates/transaction_log/index.html.eex:7
msgid "Internal Transactions"
msgstr ""
@ -351,7 +351,7 @@ msgid "Search by address, transaction hash, or block number"
msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:96
#: lib/explorer_web/templates/transaction/show.html.eex:50
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:50
msgid "There are no Internal Transactions"
msgstr ""
@ -371,11 +371,11 @@ msgstr ""
msgid "Transactions To"
msgstr ""
#: lib/explorer_web/templates/transaction/show.html.eex:27
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:27
msgid "Type"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:135
#: lib/explorer_web/templates/transaction/overview.html.eex:145
#: lib/explorer_web/views/wei_helpers.ex:82
msgid "Wei"
msgstr ""
@ -425,10 +425,11 @@ msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:31
#: lib/explorer_web/templates/chain/show.html.eex:36
#: lib/explorer_web/templates/chain/show.html.eex:40
#: lib/explorer_web/views/currency_helpers.ex:32
msgid "USD"
msgstr ""
#: lib/explorer_web/templates/address/overview.html.eex:15
#: lib/explorer_web/templates/address/overview.html.eex:16
msgid "Number of Transactions"
msgstr ""
@ -460,7 +461,7 @@ msgstr ""
msgid "Tokens"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:132
#: lib/explorer_web/templates/transaction/overview.html.eex:142
msgid "Total Gas Used"
msgstr ""
@ -476,3 +477,7 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:3
msgid "View All"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:133
msgid "TX Fee"
msgstr ""

@ -78,7 +78,7 @@ msgstr "Transactions"
#: lib/explorer_web/templates/pending_transaction/index.html.eex:40
#: lib/explorer_web/templates/transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/overview.html.eex:43
#: lib/explorer_web/templates/transaction/show.html.eex:30
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:30
msgid "Value"
msgstr "Value"
@ -92,9 +92,8 @@ msgstr "Difficulty"
#: lib/explorer_web/templates/block/index.html.eex:23
#: lib/explorer_web/templates/block_transaction/index.html.eex:95
#: lib/explorer_web/templates/block_transaction/index.html.eex:103
#: lib/explorer_web/templates/transaction/overview.html.eex:115
#: lib/explorer_web/templates/transaction/show.html.eex:31
#: lib/explorer_web/templates/transaction/overview.html.eex:116
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
msgid "Gas Limit"
msgstr "Gas Limit"
@ -102,7 +101,8 @@ msgstr "Gas Limit"
msgid "Miner"
msgstr "Validator"
#: lib/explorer_web/templates/transaction/overview.html.eex:83
#: lib/explorer_web/templates/block_transaction/index.html.eex:103
#: lib/explorer_web/templates/transaction/overview.html.eex:84
msgid "Nonce"
msgstr "Nonce"
@ -141,17 +141,17 @@ msgstr "Cumulative Gas Used"
#: lib/explorer_web/templates/block/index.html.eex:22
#: lib/explorer_web/templates/block/index.html.eex:23
#: lib/explorer_web/templates/chain/_blocks.html.eex:11
#: lib/explorer_web/templates/transaction/overview.html.eex:118
#: lib/explorer_web/templates/transaction/show.html.eex:31
#: lib/explorer_web/templates/transaction/overview.html.eex:119
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
msgid "Gas"
msgstr "Gas"
#: lib/explorer_web/templates/block/index.html.eex:24
#: lib/explorer_web/templates/transaction/overview.html.eex:123
#: lib/explorer_web/templates/transaction/overview.html.eex:124
msgid "Gas Price"
msgstr "Gas Price"
#: lib/explorer_web/templates/transaction/overview.html.eex:140
#: lib/explorer_web/templates/transaction/overview.html.eex:150
msgid "Input"
msgstr "Input"
@ -176,8 +176,8 @@ msgstr "Address"
#: lib/explorer_web/templates/chain/_transactions.html.eex:9
#: lib/explorer_web/templates/pending_transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/index.html.eex:36
#: lib/explorer_web/templates/transaction/overview.html.eex:51
#: lib/explorer_web/templates/transaction/show.html.eex:28
#: lib/explorer_web/templates/transaction/overview.html.eex:52
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:28
#: lib/explorer_web/views/address_internal_transaction_view.ex:7
#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "From"
@ -188,7 +188,7 @@ msgstr "From"
msgid "Overview"
msgstr "Overview"
#: lib/explorer_web/views/transaction_view.ex:90
#: lib/explorer_web/views/transaction_view.ex:110
msgid "Success"
msgstr "Success"
@ -200,8 +200,8 @@ msgstr "Success"
#: lib/explorer_web/templates/chain/_transactions.html.eex:10
#: lib/explorer_web/templates/pending_transaction/index.html.eex:39
#: lib/explorer_web/templates/transaction/index.html.eex:37
#: lib/explorer_web/templates/transaction/overview.html.eex:67
#: lib/explorer_web/templates/transaction/show.html.eex:29
#: lib/explorer_web/templates/transaction/overview.html.eex:68
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:29
#: lib/explorer_web/views/address_internal_transaction_view.ex:6
#: lib/explorer_web/views/address_transaction_view.ex:8
msgid "To"
@ -246,25 +246,25 @@ msgstr "Showing %{count} Transactions"
#: lib/explorer_web/templates/layout/_topnav.html.eex:33
#: lib/explorer_web/templates/pending_transaction/index.html.eex:21
#: lib/explorer_web/templates/transaction/index.html.eex:19
#: lib/explorer_web/templates/transaction/overview.html.eex:61
#: lib/explorer_web/templates/transaction/overview.html.eex:77
#: lib/explorer_web/views/transaction_view.ex:18
#: lib/explorer_web/views/transaction_view.ex:46
#: lib/explorer_web/views/transaction_view.ex:53
#: lib/explorer_web/views/transaction_view.ex:89
#: lib/explorer_web/templates/transaction/overview.html.eex:62
#: lib/explorer_web/templates/transaction/overview.html.eex:78
#: lib/explorer_web/views/transaction_view.ex:20
#: lib/explorer_web/views/transaction_view.ex:66
#: lib/explorer_web/views/transaction_view.ex:73
#: lib/explorer_web/views/transaction_view.ex:109
msgid "Pending"
msgstr "Pending"
#: lib/explorer_web/templates/transaction/overview.html.eex:97
#: lib/explorer_web/templates/transaction/overview.html.eex:98
msgid "First Seen"
msgstr ""
#: lib/explorer_web/templates/pending_transaction/index.html.eex:37
#: lib/explorer_web/templates/transaction/overview.html.eex:106
#: lib/explorer_web/templates/transaction/overview.html.eex:107
msgid "Last Seen"
msgstr ""
#: lib/explorer_web/templates/transaction/show.html.eex:14
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:14
#: lib/explorer_web/templates/transaction_log/index.html.eex:14
msgid "Logs"
msgstr ""
@ -314,11 +314,11 @@ msgstr ""
msgid "Next Page"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:87
#: lib/explorer_web/views/transaction_view.ex:107
msgid "Failed"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:88
#: lib/explorer_web/views/transaction_view.ex:108
msgid "Out of Gas"
msgstr ""
@ -341,7 +341,7 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:11
#: lib/explorer_web/templates/pending_transaction/index.html.eex:40
#: lib/explorer_web/templates/transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/show.html.eex:30
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:30
#: lib/explorer_web/views/wei_helpers.ex:84
msgid "Ether"
msgstr "POA"
@ -353,7 +353,7 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:14
#: lib/explorer_web/templates/address_transaction/index.html.eex:14
#: lib/explorer_web/templates/transaction/show.html.eex:7
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:7
#: lib/explorer_web/templates/transaction_log/index.html.eex:7
msgid "Internal Transactions"
msgstr ""
@ -363,7 +363,7 @@ msgid "Search by address, transaction hash, or block number"
msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:96
#: lib/explorer_web/templates/transaction/show.html.eex:50
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:50
msgid "There are no Internal Transactions"
msgstr ""
@ -383,11 +383,11 @@ msgstr ""
msgid "Transactions To"
msgstr ""
#: lib/explorer_web/templates/transaction/show.html.eex:27
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:27
msgid "Type"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:135
#: lib/explorer_web/templates/transaction/overview.html.eex:145
#: lib/explorer_web/views/wei_helpers.ex:82
msgid "Wei"
msgstr ""
@ -437,10 +437,11 @@ msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:31
#: lib/explorer_web/templates/chain/show.html.eex:36
#: lib/explorer_web/templates/chain/show.html.eex:40
#: lib/explorer_web/views/currency_helpers.ex:32
msgid "USD"
msgstr ""
#: lib/explorer_web/templates/address/overview.html.eex:15
#: lib/explorer_web/templates/address/overview.html.eex:16
msgid "Number of Transactions"
msgstr ""
@ -472,7 +473,7 @@ msgstr ""
msgid "Tokens"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:132
#: lib/explorer_web/templates/transaction/overview.html.eex:142
msgid "Total Gas Used"
msgstr ""
@ -488,3 +489,7 @@ msgstr ""
#: lib/explorer_web/templates/chain/_transactions.html.eex:3
msgid "View All"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:133
msgid "TX Fee"
msgstr ""

@ -3,6 +3,8 @@ defmodule ExplorerWeb.AddressInternalTransactionControllerTest do
import ExplorerWeb.Router.Helpers, only: [address_internal_transaction_path: 4]
alias Explorer.ExchangeRates.Token
describe "GET index/3" do
test "with invalid address hash", %{conn: conn} do
conn =
@ -40,5 +42,13 @@ defmodule ExplorerWeb.AddressInternalTransactionControllerTest do
assert Enum.member?(actual_transaction_ids, from_internal_transaction.id)
assert Enum.member?(actual_transaction_ids, to_internal_transaction.id)
end
test "includes USD exchange rate value for address in assigns", %{conn: conn} do
address = insert(:address)
conn = get(conn, address_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert %Token{} = conn.assigns.exchange_rate
end
end
end

@ -4,6 +4,8 @@ defmodule ExplorerWeb.AddressTransactionControllerTest do
import ExplorerWeb.Router.Helpers, only: [address_transaction_path: 4]
import ExplorerWeb.Factory
alias Explorer.ExchangeRates.Token
describe "GET index/2" do
test "with invalid address hash", %{conn: conn} do
conn = get(conn, address_transaction_path(conn, :index, :en, "invalid_address"))
@ -58,7 +60,18 @@ defmodule ExplorerWeb.AddressTransactionControllerTest do
conn = get(conn, address_transaction_path(ExplorerWeb.Endpoint, :index, :en, address))
assert html_response(conn, 200)
assert conn.status == 200
assert Enum.empty?(conn.assigns.page)
assert conn.status == 200
assert Enum.empty?(conn.assigns.page)
end
test "includes USD exchange rate value for address in assigns", %{conn: conn} do
address = insert(:address)
conn = get(conn, address_transaction_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert %Token{} = conn.assigns.exchange_rate
end
end
end

@ -1,7 +1,7 @@
defmodule ExplorerWeb.TransactionControllerTest do
use ExplorerWeb.ConnCase
import ExplorerWeb.Router.Helpers, only: [transaction_path: 4]
import ExplorerWeb.Router.Helpers, only: [transaction_path: 4, transaction_internal_transaction_path: 4]
describe "GET index/2" do
test "returns a transaction with a receipt", %{conn: conn} do
@ -73,59 +73,12 @@ defmodule ExplorerWeb.TransactionControllerTest do
end
describe "GET show/3" do
test "with invalid transaction hash", %{conn: conn} do
conn = get(conn, transaction_path(conn, :show, :en, "invalid_transaction_hash"))
test "redirects to transactions/:transaction_id/internal_transactions", %{conn: conn} do
locale = "en"
hash = "0x9"
conn = get(conn, transaction_path(ExplorerWeb.Endpoint, :show, locale, hash))
assert html_response(conn, 404)
end
test "with valid transaction hash without transaction", %{conn: conn} do
conn =
get(
conn,
transaction_path(conn, :show, :en, "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6")
)
assert html_response(conn, 404)
end
test "when there is an associated block, it returns a transaction with block data", %{
conn: conn
} do
block = insert(:block, %{number: 777})
transaction = insert(:transaction, block_hash: block.hash, index: 0)
conn = get(conn, transaction_path(conn, :show, :en, transaction))
assert html_response(conn, 200)
assert transaction.hash == conn.assigns.transaction.hash
assert block.number == conn.assigns.transaction.block.number
end
test "returns a transaction without associated block data", %{conn: conn} do
transaction = insert(:transaction)
conn = get(conn, transaction_path(conn, :show, :en, transaction))
assert html_response(conn, 200)
assert transaction.hash == conn.assigns.transaction.hash
end
test "returns internal transactions for the transaction", %{conn: conn} do
transaction = insert(:transaction)
expected_internal_transaction = insert(:internal_transaction, transaction_hash: transaction.hash, index: 0)
insert(:internal_transaction, transaction_hash: transaction.hash, index: 1)
path = transaction_path(ExplorerWeb.Endpoint, :show, :en, transaction)
conn = get(conn, path)
actual_internal_transaction_ids =
conn.assigns.internal_transactions.entries
|> Enum.map(fn it -> it.id end)
assert conn.assigns.transaction.hash == transaction.hash
assert Enum.member?(actual_internal_transaction_ids, expected_internal_transaction.id)
assert redirected_to(conn) =~ transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, locale, hash)
end
end
end

@ -0,0 +1,62 @@
defmodule ExplorerWeb.TransactionInternalTransactionControllerTest do
use ExplorerWeb.ConnCase
import ExplorerWeb.Router.Helpers, only: [transaction_internal_transaction_path: 4]
alias Explorer.ExchangeRates.Token
describe "GET index/3" do
test "with missing transaction", %{conn: conn} do
hash = transaction_hash()
conn = get(conn, transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, hash))
assert html_response(conn, 404)
end
test "with invalid transaction hash", %{conn: conn} do
conn = get(conn, transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, "nope"))
assert html_response(conn, 404)
end
test "includes transaction data", %{conn: conn} do
block = insert(:block, %{number: 777})
transaction =
:transaction
|> insert()
|> with_block(block)
conn = get(conn, transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, transaction.hash))
assert html_response(conn, 200)
assert conn.assigns.transaction.hash == transaction.hash
end
test "includes internal transactions for the transaction", %{conn: conn} do
transaction = insert(:transaction)
expected_internal_transaction = insert(:internal_transaction, transaction_hash: transaction.hash, index: 0)
insert(:internal_transaction, transaction_hash: transaction.hash, index: 1)
path = transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, transaction.hash)
conn = get(conn, path)
actual_internal_transaction_ids =
conn.assigns.internal_transactions.entries
|> Enum.map(fn it -> it.id end)
assert html_response(conn, 200)
assert Enum.member?(actual_internal_transaction_ids, expected_internal_transaction.id)
end
test "includes USD exchange rate value for address in assigns", %{conn: conn} do
transaction = insert(:transaction)
conn = get(conn, transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, transaction.hash))
assert %Token{} = conn.assigns.exchange_rate
end
end
end

@ -3,6 +3,8 @@ defmodule ExplorerWeb.TransactionLogControllerTest do
import ExplorerWeb.Router.Helpers, only: [transaction_log_path: 4]
alias Explorer.ExchangeRates.Token
describe "GET index/2" do
test "with invalid transaction hash", %{conn: conn} do
conn = get(conn, transaction_log_path(conn, :index, :en, "invalid_transaction_string"))
@ -42,4 +44,12 @@ defmodule ExplorerWeb.TransactionLogControllerTest do
assert Enum.count(conn.assigns.logs.entries) == 0
end
end
test "includes USD exchange rate value for address in assigns", %{conn: conn} do
transaction = insert(:transaction)
conn = get(conn, transaction_log_path(ExplorerWeb.Endpoint, :index, :en, transaction.hash))
assert %Token{} = conn.assigns.exchange_rate
end
end

@ -0,0 +1,42 @@
defmodule ExplorerWeb.ExchangeRates.USDTest do
use ExUnit.Case, async: true
alias ExplorerWeb.ExchangeRates.USD
alias Explorer.ExchangeRates.Token
alias Explorer.Chain.Wei
describe "from/2" do
test "with nil wei returns null object" do
token = %Token{usd_value: Decimal.new(0.5)}
assert USD.null() == USD.from(nil, token)
end
test "with nil token returns nil" do
wei = %Wei{value: Decimal.new(10_000_000_000_000)}
assert USD.null() == USD.from(wei, nil)
end
test "without a wei value returns nil" do
wei = %Wei{value: nil}
token = %Token{usd_value: Decimal.new(0.5)}
assert USD.null() == USD.from(wei, token)
end
test "without an exchange rate returns nil" do
wei = %Wei{value: Decimal.new(10_000_000_000_000)}
token = %Token{usd_value: nil}
assert USD.null() == USD.from(wei, token)
end
test "returns formatted usd value" do
wei = %Wei{value: Decimal.new(10_000_000_000_000)}
token = %Token{usd_value: Decimal.new(0.5)}
assert %USD{value: Decimal.new(0.000005)} == USD.from(wei, token)
end
end
end

@ -0,0 +1,26 @@
defmodule ExplorerWeb.AddressViewTest do
use ExplorerWeb.ConnCase, async: true
alias ExplorerWeb.AddressView
alias Explorer.ExchangeRates.Token
describe "formatted_usd/2" do
test "without a fetched_balance returns nil" do
address = build(:address, fetched_balance: nil)
token = %Token{usd_value: Decimal.new(0.5)}
assert nil == AddressView.formatted_usd(address, token)
end
test "without a usd_value returns nil" do
address = build(:address)
token = %Token{usd_value: nil}
assert nil == AddressView.formatted_usd(address, token)
end
test "returns formatted usd value" do
address = build(:address, fetched_balance: 10_000_000_000_000)
token = %Token{usd_value: Decimal.new(0.5)}
assert "$0.000005 USD" == AddressView.formatted_usd(address, token)
end
end
end

@ -0,0 +1,16 @@
defmodule ExplorerWeb.CurrencyHelpersTest do
use ExUnit.Case
alias ExplorerWeb.CurrencyHelpers
alias ExplorerWeb.ExchangeRates.USD
doctest ExplorerWeb.CurrencyHelpers, import: true
test "with nil it returns nil" do
assert nil == CurrencyHelpers.format_usd_value(nil)
end
test "with USD.null() it returns nil" do
assert nil == CurrencyHelpers.format_usd_value(USD.null())
end
end

@ -1,10 +1,45 @@
defmodule ExplorerWeb.TransactionViewTest do
use ExplorerWeb.ConnCase, async: true
alias Explorer.Chain.Transaction
alias Explorer.Chain.{Transaction, Wei}
alias Explorer.ExchangeRates.Token
alias Explorer.Repo
alias ExplorerWeb.TransactionView
describe "formatted_fee/2" do
test "pending transaction with no Receipt" do
{:ok, gas_price} = Wei.cast(3_000_000_000)
transaction =
build(
:transaction,
gas_price: gas_price,
gas: Decimal.new(3_000_000),
receipt: nil
)
token = %Token{usd_value: Decimal.new(0.50)}
expected_value = "<= 0.009,000,000,000,000,000 POA"
assert expected_value == TransactionView.formatted_fee(transaction, denomination: :ether)
assert "<= $0.0045 USD" == TransactionView.formatted_fee(transaction, exchange_rate: token)
end
test "with fee and exchange_rate" do
{:ok, gas_price} = Wei.cast(3_000_000_000)
receipt = build(:receipt, gas_used: Decimal.new(1_034_234.0))
transaction = build(:transaction, gas_price: gas_price, receipt: receipt)
token = %Token{usd_value: Decimal.new(0.50)}
expected_value = "0.003,102,702,000,000,000 POA"
assert expected_value == TransactionView.formatted_fee(transaction, denomination: :ether)
assert "$0.001551351 USD" == TransactionView.formatted_fee(transaction, exchange_rate: token)
end
test "with fee but no available exchange_rate" do
end
end
describe "formatted_status/1" do
test "without receipt" do
transaction =

@ -25,6 +25,7 @@ defmodule ExplorerWeb.ConnCase do
@endpoint ExplorerWeb.Endpoint
import Explorer.Factory
import ExplorerWeb.Factory
end
end

@ -28,6 +28,9 @@ defmodule ExplorerWeb.Factory do
where: transaction.block_hash == ^block_hash
)
Repo.one!(query) + 1
case Repo.one(query) do
nil -> 0
index -> index + 1
end
end
end

Loading…
Cancel
Save