Add Wei Ecto type (#145)

* Add Wei Ecto type

* Add view helper for manipulating Wei values

* Update templates to use Wei helpers
pull/175/head
Alex Garibay 7 years ago committed by GitHub
parent fcf0572b47
commit 025bec4226
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      apps/explorer/lib/explorer/chain.ex
  2. 6
      apps/explorer/lib/explorer/chain/address.ex
  3. 5
      apps/explorer/lib/explorer/chain/credit.ex
  4. 4
      apps/explorer/lib/explorer/chain/debit.ex
  5. 2
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  6. 6
      apps/explorer/lib/explorer/chain/transaction.ex
  7. 129
      apps/explorer/lib/explorer/chain/wei.ex
  8. 4
      apps/explorer/test/explorer/chain/credit_test.exs
  9. 4
      apps/explorer/test/explorer/chain/debit_test.exs
  10. 52
      apps/explorer/test/explorer/chain/wei_test.exs
  11. 58
      apps/explorer/test/explorer/chain_test.exs
  12. 4
      apps/explorer/test/explorer/importers/balance_importer_test.exs
  13. 6
      apps/explorer/test/explorer/importers/transaction_importer_test.exs
  14. 6
      apps/explorer/test/explorer/workers/import_balance_test.exs
  15. 10
      apps/explorer/test/explorer/workers/refresh_balance_test.exs
  16. 2
      apps/explorer_web/lib/explorer_web.ex
  17. 2
      apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
  18. 4
      apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
  19. 8
      apps/explorer_web/lib/explorer_web/templates/block/index.html.eex
  20. 2
      apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
  21. 2
      apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex
  22. 2
      apps/explorer_web/lib/explorer_web/templates/pending_transaction/index.html.eex
  23. 2
      apps/explorer_web/lib/explorer_web/templates/transaction/index.html.eex
  24. 6
      apps/explorer_web/lib/explorer_web/templates/transaction/overview.html.eex
  25. 2
      apps/explorer_web/lib/explorer_web/templates/transaction/show.html.eex
  26. 5
      apps/explorer_web/lib/explorer_web/views/address_transaction_view.ex
  27. 16
      apps/explorer_web/lib/explorer_web/views/address_view.ex
  28. 1
      apps/explorer_web/lib/explorer_web/views/block_transaction_view.ex
  29. 17
      apps/explorer_web/lib/explorer_web/views/block_view.ex
  30. 4
      apps/explorer_web/lib/explorer_web/views/chain_view.ex
  31. 2
      apps/explorer_web/lib/explorer_web/views/pending_transaction_view.ex
  32. 42
      apps/explorer_web/lib/explorer_web/views/transaction_view.ex
  33. 93
      apps/explorer_web/lib/explorer_web/views/wei_helpers.ex
  34. 32
      apps/explorer_web/priv/gettext/default.pot
  35. 32
      apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
  36. 60
      apps/explorer_web/test/explorer_web/views/address_transaction_view_test.exs
  37. 8
      apps/explorer_web/test/explorer_web/views/wei_helpers_test.exs

@ -108,7 +108,7 @@ defmodule Explorer.Chain do
@doc """
The `t:Explorer.Chain.Address.t/0` `balance` in `unit`.
"""
@spec balance(Address.t(), :wei) :: Wei.t() | nil
@spec balance(Address.t(), :wei) :: Wei.wei() | nil
@spec balance(Address.t(), :gwei) :: Wei.gwei() | nil
@spec balance(Address.t(), :ether) :: Wei.ether() | nil
def balance(%Address{balance: balance}, unit) do
@ -253,9 +253,9 @@ defmodule Explorer.Chain do
@spec fee(%Transaction{receipt: nil}, :ether | :gwei | :wei) :: {:maximum, Decimal.t()}
def fee(%Transaction{gas: gas, gas_price: gas_price, receipt: nil}, unit) do
fee =
gas
|> Decimal.mult(gas_price)
gas_price
|> Wei.to(unit)
|> Decimal.mult(gas)
{:maximum, fee}
end
@ -263,9 +263,9 @@ defmodule Explorer.Chain do
@spec fee(%Transaction{receipt: Receipt.t()}, :ether | :gwei | :wei) :: {:actual, Decimal.t()}
def fee(%Transaction{gas_price: gas_price, receipt: %Receipt{gas_used: gas_used}}, unit) do
fee =
gas_used
|> Decimal.mult(gas_price)
gas_price
|> Wei.to(unit)
|> Decimal.mult(gas_used)
{:actual, fee}
end
@ -273,7 +273,7 @@ defmodule Explorer.Chain do
@doc """
The `t:Explorer.Chain.Transaction.t/0` `gas_price` of the `transaction` in `unit`.
"""
@spec gas_price(Transaction.t(), :wei) :: Wei.t()
@spec gas_price(Transaction.t(), :wei) :: Wei.wei()
@spec gas_price(Transaction.t(), :gwei) :: Wei.gwei()
@spec gas_price(Transaction.t(), :ether) :: Wei.ether()
def gas_price(%Transaction{gas_price: gas_price}, unit) do
@ -570,10 +570,10 @@ defmodule Explorer.Chain do
The `t:Explorer.Chain.Transaction.t/0` or `t:Explorer.Chain.InternalTransaction.t/0` `value` of the `transaction` in
`unit`.
"""
@spec value(InternalTransaction.t(), :wei) :: Wei.t()
@spec value(InternalTransaction.t(), :wei) :: Wei.wei()
@spec value(InternalTransaction.t(), :gwei) :: Wei.gwei()
@spec value(InternalTransaction.t(), :ether) :: Wei.ether()
@spec value(Transaction.t(), :wei) :: Wei.t()
@spec value(Transaction.t(), :wei) :: Wei.wei()
@spec value(Transaction.t(), :gwei) :: Wei.gwei()
@spec value(Transaction.t(), :ether) :: Wei.ether()
def value(%type{value: value}, unit) when type in [InternalTransaction, Transaction] do

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Address do
use Explorer.Schema
alias Explorer.Chain.{Credit, Debit}
alias Explorer.Chain.{Credit, Debit, Hash, Wei}
@typedoc """
Hash of the public key for this address.
@ -21,7 +21,7 @@ defmodule Explorer.Chain.Address do
* `updated_at` when this address was last updated
"""
@type t :: %__MODULE__{
balance: Decimal.t(),
balance: Wei.t(),
balance_updated_at: DateTime.t(),
credit: Ecto.Association.NotLoaded.t() | Credit.t() | nil,
debit: Ecto.Association.NotLoaded.t() | Debit.t() | nil,
@ -31,7 +31,7 @@ defmodule Explorer.Chain.Address do
}
schema "addresses" do
field(:balance, :decimal)
field(:balance, Wei)
field(:balance_updated_at, Timex.Ecto.DateTime)
field(:hash, :string)

@ -6,13 +6,14 @@ defmodule Explorer.Chain.Credit do
use Explorer.Schema
alias Ecto.Adapters.SQL
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Wei}
alias Explorer.Repo
@primary_key false
schema "credits" do
field(:count, :integer)
field(:value, :decimal)
field(:value, Wei)
timestamps()

@ -6,13 +6,13 @@ defmodule Explorer.Chain.Debit do
use Explorer.Schema
alias Ecto.Adapters.SQL
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Wei}
alias Explorer.Repo
@primary_key false
schema "debits" do
field(:count, :integer)
field(:value, :decimal)
field(:value, Wei)
timestamps()

@ -55,7 +55,7 @@ defmodule Explorer.Chain.InternalTransaction do
field(:input, :string)
field(:output, :string)
field(:trace_address, {:array, :integer})
field(:value, :decimal)
field(:value, Wei)
timestamps()

@ -73,7 +73,7 @@ defmodule Explorer.Chain.Transaction do
@typedoc """
How much the sender is willing to pay in wei per unit of gas.
"""
@type wei_per_gas :: non_neg_integer()
@type wei_per_gas :: Wei.t()
@typedoc """
* `block_transaction` - joins this transaction to its `block`
@ -125,7 +125,7 @@ defmodule Explorer.Chain.Transaction do
schema "transactions" do
field(:gas, :decimal)
field(:gas_price, :decimal)
field(:gas_price, Wei)
field(:hash, :string)
field(:input, :string)
field(:nonce, :integer)
@ -135,7 +135,7 @@ defmodule Explorer.Chain.Transaction do
field(:standard_v, :string)
field(:transaction_index, :string)
field(:v, :string)
field(:value, :decimal)
field(:value, Wei)
timestamps()

@ -3,11 +3,82 @@ defmodule Explorer.Chain.Wei do
The smallest fractional unit of Ether. Using wei instead of ether allows code to do integer match instead of using
floats.
All values represented by the `Wei` struct are assumed to measured in the base unit of wei.
See [Etherum Homestead Documentation](http://ethdocs.org/en/latest/ether.html) for examples of various denominations of wei.
Etymology of "wei" comes from [Wei Dai ()](https://en.wikipedia.org/wiki/Wei_Dai), a
[cypherpunk](https://en.wikipedia.org/wiki/Cypherpunk) who came up with b-money, which outlined modern
cryptocurrencies.
## Interfacing With Ecto
You can define a field in a schema to be of type Wei for convinience when dealing with Wei values.
schema "my_schema" do
field :gas, Explorer.Chain.Wei
end
"""
defstruct ~w(value)a
@behaviour Ecto.Type
@impl Ecto.Type
def type, do: :decimal
@impl Ecto.Type
def cast("0x" <> hex_wei) do
with {int_wei, ""} <- Integer.parse(hex_wei, 16) do
decimal = Decimal.new(int_wei)
{:ok, %__MODULE__{value: decimal}}
else
_ -> :error
end
end
@impl Ecto.Type
def cast(string_wei) when is_binary(string_wei) do
with {int_wei, ""} <- Integer.parse(string_wei) do
decimal = Decimal.new(int_wei)
{:ok, %__MODULE__{value: decimal}}
else
_ -> :error
end
end
@impl Ecto.Type
def cast(int_wei) when is_integer(int_wei) do
decimal = Decimal.new(int_wei)
{:ok, %__MODULE__{value: decimal}}
end
@impl Ecto.Type
def cast(%Decimal{} = decimal) do
{:ok, %__MODULE__{value: decimal}}
end
@impl Ecto.Type
def cast(%__MODULE__{} = wei) do
{:ok, wei}
end
@impl Ecto.Type
def cast(_), do: :error
@impl Ecto.Type
def dump(%__MODULE__{value: %Decimal{} = decimal}) do
{:ok, decimal}
end
@impl Ecto.Type
def dump(_), do: :error
@impl Ecto.Type
def load(%Decimal{} = decimal) do
{:ok, %__MODULE__{value: decimal}}
end
@typedoc """
Ether is the default unit Ethereum and its side chains are measured in when displaying values to humans.
@ -27,8 +98,15 @@ defmodule Explorer.Chain.Wei do
"""
@type unit :: :wei | :gwei | :ether
@typedoc """
The smallest fractional unit of Ether.
"""
@type wei :: Decimal.t()
@typedoc @moduledoc
@type t :: Decimal.t()
@type t :: %__MODULE__{
value: Decimal.t()
}
# Constants
@ -38,68 +116,85 @@ defmodule Explorer.Chain.Wei do
## Functions
@doc """
Converts `Decimal` representations of various wei denominations (wei, Gwei, ether) to
a wei base unit.
## Examples
Convert wei to itself.
iex> Explorer.Chain.Wei.from(Decimal.new(1), :wei)
Decimal.new(1)
%Explorer.Chain.Wei{value: Decimal.new(1)}
Convert `t:gwei/0` to wei.
iex> Explorer.Chain.Wei.from(Decimal.new(1), :gwei)
Decimal.new(1_000_000_000)
%Explorer.Chain.Wei{value: Decimal.new(1_000_000_000)}
Convert `t:ether/0` to wei.
iex> Explorer.Chain.Wei.from(Decimal.new(1), :ether)
Decimal.new(1_000_000_000_000_000_000)
%Explorer.Chain.Wei{value: Decimal.new(1_000_000_000_000_000_000)}
"""
@spec from(ether(), :ether) :: t()
def from(ether, :ether) do
Decimal.mult(ether, @wei_per_ether)
def from(%Decimal{} = ether, :ether) do
%__MODULE__{value: Decimal.mult(ether, @wei_per_ether)}
end
@spec from(gwei(), :gwei) :: t()
def from(gwei, :gwei) do
Decimal.mult(gwei, @wei_per_gwei)
def from(%Decimal{} = gwei, :gwei) do
%__MODULE__{value: Decimal.mult(gwei, @wei_per_gwei)}
end
@spec from(t(), :wei) :: t()
def from(wei, :wei), do: wei
def from(%Decimal{} = wei, :wei) do
%__MODULE__{value: wei}
end
@doc """
Converts a `Wei` value to another denomination of wei represented in `Decimal`.
## Examples
Convert wei to itself.
iex> Explorer.Chain.Wei.to(Decimal.new(1), :wei)
iex> Explorer.Chain.Wei.to(%Explorer.Chain.Wei{value: Decimal.new(1)}, :wei)
Decimal.new(1)
Convert wei to `t:gwei/0`.
iex> Explorer.Chain.Wei.to(Decimal.new(1), :gwei)
iex> Explorer.Chain.Wei.to(%Explorer.Chain.Wei{value: Decimal.new(1)}, :gwei)
Decimal.new("1e-9")
iex> Explorer.Chain.Wei.to(Decimal.new("1e9"), :gwei)
iex> Explorer.Chain.Wei.to(%Explorer.Chain.Wei{value: Decimal.new("1e9")}, :gwei)
Decimal.new(1)
Convert wei to `t:ether/0`.
iex> Explorer.Chain.Wei.to(Decimal.new(1), :ether)
iex> Explorer.Chain.Wei.to(%Explorer.Chain.Wei{value: Decimal.new(1)}, :ether)
Decimal.new("1e-18")
iex> Explorer.Chain.Wei.to(Decimal.new("1e18"), :ether)
iex> Explorer.Chain.Wei.to(%Explorer.Chain.Wei{value: Decimal.new("1e18")}, :ether)
Decimal.new(1)
"""
@spec to(t(), :ether) :: ether()
def to(wei, :ether) do
def to(%__MODULE__{value: wei}, :ether) do
Decimal.div(wei, @wei_per_ether)
end
@spec to(t(), :gwei) :: gwei()
def to(wei, :gwei) do
def to(%__MODULE__{value: wei}, :gwei) do
Decimal.div(wei, @wei_per_gwei)
end
@spec to(t(), :wei) :: t()
def to(wei, :wei), do: wei
def to(%__MODULE__{value: wei}, :wei), do: wei
end
defimpl Inspect, for: Explorer.Chain.Wei do
def inspect(wei, _) do
"#Explorer.Chain.Wei<#{Decimal.to_string(wei.value)}>"
end
end

@ -1,7 +1,7 @@
defmodule Explorer.Chain.CreditTest do
use Explorer.DataCase
alias Explorer.Chain.Credit
alias Explorer.Chain.{Credit, Wei}
describe "Repo.all/1" do
test "returns no rows when there are no addresses" do
@ -47,7 +47,7 @@ defmodule Explorer.Chain.CreditTest do
address_id = recipient.id
Credit.refresh()
credit = Credit |> where(address_id: ^address_id) |> Repo.one()
assert credit.value == Decimal.new(21)
assert credit.value == %Wei{value: Decimal.new(21)}
end
end
end

@ -1,7 +1,7 @@
defmodule Explorer.Chain.DebitTest do
use Explorer.DataCase
alias Explorer.Chain.Debit
alias Explorer.Chain.{Debit, Wei}
describe "Repo.all/1" do
test "returns no rows when there are no addresses" do
@ -34,7 +34,7 @@ defmodule Explorer.Chain.DebitTest do
address_id = sender.id
Debit.refresh()
debit = Debit |> where(address_id: ^address_id) |> Repo.one()
assert debit.value == Decimal.new(21)
assert debit.value == %Wei{value: Decimal.new(21)}
end
test "returns no debits against the recipient" do

@ -1,5 +1,57 @@
defmodule Explorer.Chain.WeiTest do
use ExUnit.Case, async: true
alias Explorer.Chain.Wei
doctest Explorer.Chain.Wei
describe "cast/1" do
test "with hex string" do
assert Wei.cast("0x142") == {:ok, %Wei{value: Decimal.new(322)}}
assert Wei.cast("0xzzz") == :error
end
test "with integer string" do
assert Wei.cast("123") == {:ok, %Wei{value: Decimal.new(123)}}
assert Wei.cast("123.5") == :error
assert Wei.cast("invalid") == :error
end
test "with integer" do
assert Wei.cast(123) == {:ok, %Wei{value: Decimal.new(123)}}
end
test "with decimal" do
decimal = Decimal.new(123)
assert Wei.cast(decimal) == {:ok, %Wei{value: decimal}}
end
test "with Wei struct" do
wei = %Wei{value: Decimal.new(123)}
assert Wei.cast(wei) == {:ok, wei}
end
test "with unsupported type" do
assert Wei.cast(nil) == :error
end
end
describe "dump/1" do
test "with Wei struct" do
decimal = Decimal.new(123)
assert Wei.dump(%Wei{value: decimal}) == {:ok, decimal}
end
test "with invalid value" do
assert Wei.dump(123) == :error
end
end
test "load/1" do
decimal = Decimal.new(123)
assert Wei.load(decimal) == {:ok, %Wei{value: decimal}}
end
test "type/0" do
assert Wei.type() == :decimal
end
end

@ -3,7 +3,7 @@ defmodule Explorer.ChainTest do
alias Explorer.{Chain, Repo}
alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Receipt, Transaction}
alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Receipt, Transaction, Wei}
# Constants
@ -155,19 +155,19 @@ defmodule Explorer.ChainTest do
describe "balance/2" do
test "with Address.t with :wei" do
assert Chain.balance(%Address{balance: Decimal.new(1)}, :wei) == Decimal.new(1)
assert Chain.balance(%Address{balance: %Wei{value: Decimal.new(1)}}, :wei) == Decimal.new(1)
assert Chain.balance(%Address{balance: nil}, :wei) == nil
end
test "with Address.t with :gwei" do
assert Chain.balance(%Address{balance: Decimal.new(1)}, :gwei) == Decimal.new("1e-9")
assert Chain.balance(%Address{balance: Decimal.new("1e9")}, :gwei) == Decimal.new(1)
assert Chain.balance(%Address{balance: %Wei{value: Decimal.new(1)}}, :gwei) == Decimal.new("1e-9")
assert Chain.balance(%Address{balance: %Wei{value: Decimal.new("1e9")}}, :gwei) == Decimal.new(1)
assert Chain.balance(%Address{balance: nil}, :gwei) == nil
end
test "with Address.t with :ether" do
assert Chain.balance(%Address{balance: Decimal.new(1)}, :ether) == Decimal.new("1e-18")
assert Chain.balance(%Address{balance: Decimal.new("1e18")}, :ether) == Decimal.new(1)
assert Chain.balance(%Address{balance: %Wei{value: Decimal.new(1)}}, :ether) == Decimal.new("1e-18")
assert Chain.balance(%Address{balance: %Wei{value: Decimal.new("1e18")}}, :ether) == Decimal.new(1)
assert Chain.balance(%Address{balance: nil}, :ether) == nil
end
end
@ -342,17 +342,17 @@ defmodule Explorer.ChainTest do
describe "fee/2" do
test "without receipt with :wei unit" do
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: Decimal.new(2), receipt: nil}, :wei) ==
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: %Wei{value: Decimal.new(2)}, receipt: nil}, :wei) ==
{:maximum, Decimal.new(6)}
end
test "without receipt with :gwei unit" do
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: Decimal.new(2), receipt: nil}, :gwei) ==
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: %Wei{value: Decimal.new(2)}, receipt: nil}, :gwei) ==
{:maximum, Decimal.new("6e-9")}
end
test "without receipt with :ether unit" do
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: Decimal.new(2), receipt: nil}, :ether) ==
assert Chain.fee(%Transaction{gas: Decimal.new(3), gas_price: %Wei{value: Decimal.new(2)}, receipt: nil}, :ether) ==
{:maximum, Decimal.new("6e-18")}
end
@ -360,7 +360,7 @@ defmodule Explorer.ChainTest do
assert Chain.fee(
%Transaction{
gas: Decimal.new(3),
gas_price: Decimal.new(2),
gas_price: %Wei{value: Decimal.new(2)},
receipt: %Receipt{gas_used: Decimal.new(2)}
},
:wei
@ -371,7 +371,7 @@ defmodule Explorer.ChainTest do
assert Chain.fee(
%Transaction{
gas: Decimal.new(3),
gas_price: Decimal.new(2),
gas_price: %Wei{value: Decimal.new(2)},
receipt: %Receipt{gas_used: Decimal.new(2)}
},
:gwei
@ -382,7 +382,7 @@ defmodule Explorer.ChainTest do
assert Chain.fee(
%Transaction{
gas: Decimal.new(3),
gas_price: Decimal.new(2),
gas_price: %Wei{value: Decimal.new(2)},
receipt: %Receipt{gas_used: Decimal.new(2)}
},
:ether
@ -392,19 +392,19 @@ defmodule Explorer.ChainTest do
describe "gas_price/2" do
test ":wei unit" do
assert Chain.gas_price(%Transaction{gas_price: Decimal.new(1)}, :wei) == Decimal.new(1)
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new(1)}}, :wei) == Decimal.new(1)
end
test ":gwei unit" do
assert Chain.gas_price(%Transaction{gas_price: Decimal.new(1)}, :gwei) == Decimal.new("1e-9")
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new(1)}}, :gwei) == Decimal.new("1e-9")
assert Chain.gas_price(%Transaction{gas_price: Decimal.new("1e9")}, :gwei) == Decimal.new(1)
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new("1e9")}}, :gwei) == Decimal.new(1)
end
test ":ether unit" do
assert Chain.gas_price(%Transaction{gas_price: Decimal.new(1)}, :ether) == Decimal.new("1e-18")
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new(1)}}, :ether) == Decimal.new("1e-18")
assert Chain.gas_price(%Transaction{gas_price: Decimal.new("1e18")}, :ether) == Decimal.new(1)
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new("1e18")}}, :ether) == Decimal.new(1)
end
end
@ -911,7 +911,7 @@ defmodule Explorer.ChainTest do
Chain.update_balance(hash, 5)
expected_balance = Decimal.new(5)
expected_balance = %Wei{value: Decimal.new(5)}
assert {:ok, %Address{balance: ^expected_balance}} = Chain.hash_to_address(hash)
end
@ -930,7 +930,7 @@ defmodule Explorer.ChainTest do
test "creates an address if one does not exist" do
Chain.update_balance("0xtwizzlers", 88)
expected_balance = Decimal.new(88)
expected_balance = %Wei{value: Decimal.new(88)}
assert {:ok, %Address{balance: ^expected_balance}} = Chain.hash_to_address("0xtwizzlers")
end
@ -938,33 +938,33 @@ defmodule Explorer.ChainTest do
describe "value/2" do
test "with InternalTransaction.t with :wei" do
assert Chain.value(%InternalTransaction{value: Decimal.new(1)}, :wei) == Decimal.new(1)
assert Chain.value(%InternalTransaction{value: %Wei{value: Decimal.new(1)}}, :wei) == Decimal.new(1)
end
test "with InternalTransaction.t with :gwei" do
assert Chain.value(%InternalTransaction{value: Decimal.new(1)}, :gwei) == Decimal.new("1e-9")
assert Chain.value(%InternalTransaction{value: %Wei{value: Decimal.new(1)}}, :gwei) == Decimal.new("1e-9")
assert Chain.value(%InternalTransaction{value: Decimal.new("1e9")}, :gwei) == Decimal.new(1)
assert Chain.value(%InternalTransaction{value: %Wei{value: Decimal.new("1e9")}}, :gwei) == Decimal.new(1)
end
test "with InternalTransaction.t with :ether" do
assert Chain.value(%InternalTransaction{value: Decimal.new(1)}, :ether) == Decimal.new("1e-18")
assert Chain.value(%InternalTransaction{value: %Wei{value: Decimal.new(1)}}, :ether) == Decimal.new("1e-18")
assert Chain.value(%InternalTransaction{value: Decimal.new("1e18")}, :ether) == Decimal.new(1)
assert Chain.value(%InternalTransaction{value: %Wei{value: Decimal.new("1e18")}}, :ether) == Decimal.new(1)
end
test "with Transaction.t with :wei" do
assert Chain.value(%Transaction{value: Decimal.new(1)}, :wei) == Decimal.new(1)
assert Chain.value(%Transaction{value: %Wei{value: Decimal.new(1)}}, :wei) == Decimal.new(1)
end
test "with Transaction.t with :gwei" do
assert Chain.value(%Transaction{value: Decimal.new(1)}, :gwei) == Decimal.new("1e-9")
assert Chain.value(%Transaction{value: Decimal.new("1e9")}, :gwei) == Decimal.new(1)
assert Chain.value(%Transaction{value: %Wei{value: Decimal.new(1)}}, :gwei) == Decimal.new("1e-9")
assert Chain.value(%Transaction{value: %Wei{value: Decimal.new("1e9")}}, :gwei) == Decimal.new(1)
end
test "with Transaction.t with :ether" do
assert Chain.value(%Transaction{value: Decimal.new(1)}, :ether) == Decimal.new("1e-18")
assert Chain.value(%Transaction{value: Decimal.new("1e18")}, :ether) == Decimal.new(1)
assert Chain.value(%Transaction{value: %Wei{value: Decimal.new(1)}}, :ether) == Decimal.new("1e-18")
assert Chain.value(%Transaction{value: %Wei{value: Decimal.new("1e18")}}, :ether) == Decimal.new(1)
end
end
end

@ -2,7 +2,7 @@ defmodule Explorer.BalanceImporterTest do
use Explorer.DataCase
alias Explorer.{Chain, BalanceImporter}
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Wei}
describe "import/1" do
test "it updates the balance for an address" do
@ -10,7 +10,7 @@ defmodule Explorer.BalanceImporterTest do
BalanceImporter.import("0x5cc18cc34175d358ff8e19b7f98566263c4106a0")
expected_balance = Decimal.new(1_572_374_181_095_000_000)
expected_balance = %Wei{value: Decimal.new(1_572_374_181_095_000_000)}
assert {:ok, %Address{balance: ^expected_balance}} =
Chain.hash_to_address("0x5cc18cc34175d358ff8e19b7f98566263c4106a0")

@ -1,7 +1,7 @@
defmodule Explorer.TransactionImporterTest do
use Explorer.DataCase
alias Explorer.Chain.{Address, BlockTransaction, Transaction}
alias Explorer.Chain.{Address, BlockTransaction, Transaction, Wei}
alias Explorer.TransactionImporter
@raw_transaction %{
@ -188,8 +188,8 @@ defmodule Explorer.TransactionImporterTest do
from_address = Address |> Repo.get_by(hash: "0xb2867180771b196518651c174c9240d5e8bd0ecd")
to_address = Address |> Repo.get_by(hash: "0x24e5b8528fe83257d5fe3497ef616026713347f8")
assert(from_address.balance == Decimal.new(1_572_374_181_095_000_000))
assert(to_address.balance == Decimal.new(1_572_374_181_095_000_000))
assert(from_address.balance == %Wei{value: Decimal.new(1_572_374_181_095_000_000)})
assert(to_address.balance == %Wei{value: Decimal.new(1_572_374_181_095_000_000)})
end
end

@ -2,7 +2,7 @@ defmodule Explorer.Workers.ImportBalanceTest do
import Mock
alias Explorer.Chain
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Wei}
alias Explorer.Workers.ImportBalance
use Explorer.DataCase
@ -11,7 +11,7 @@ defmodule Explorer.Workers.ImportBalanceTest do
test "imports the balance for an address" do
ImportBalance.perform("0x1d12e5716c593b156eb7152ca4360f6224ba3b0a")
expected_balance = Decimal.new(1_572_374_181_095_000_000)
expected_balance = %Wei{value: Decimal.new(1_572_374_181_095_000_000)}
assert {:ok, %Address{balance: ^expected_balance}} =
Chain.hash_to_address("0x1d12e5716c593b156eb7152ca4360f6224ba3b0a")
@ -30,7 +30,7 @@ defmodule Explorer.Workers.ImportBalanceTest do
end do
ImportBalance.perform_later("0xskateboards")
expected_balance = Decimal.new(66)
expected_balance = %Wei{value: Decimal.new(66)}
assert {:ok, %Address{balance: ^expected_balance}} = Chain.hash_to_address("0xskateboards")
end

@ -3,7 +3,7 @@ defmodule Explorer.Workers.RefreshBalanceTest do
import Mock
alias Explorer.Chain.{Credit, Debit}
alias Explorer.Chain.{Credit, Debit, Wei}
alias Explorer.Workers.RefreshBalance
describe "perform/0" do
@ -14,7 +14,7 @@ defmodule Explorer.Workers.RefreshBalanceTest do
insert(:to_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform()
assert Repo.one(Credit).value == Decimal.new(20)
assert Repo.one(Credit).value == %Wei{value: Decimal.new(20)}
end
end
@ -25,7 +25,7 @@ defmodule Explorer.Workers.RefreshBalanceTest do
insert(:from_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform()
assert Repo.one(Debit).value == Decimal.new(20)
assert Repo.one(Debit).value == %Wei{value: Decimal.new(20)}
end
end
end
@ -37,7 +37,7 @@ defmodule Explorer.Workers.RefreshBalanceTest do
insert(:to_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform("credit")
assert Repo.one(Credit).value == Decimal.new(20)
assert Repo.one(Credit).value == %Wei{value: Decimal.new(20)}
end
test "refreshes debit balances" do
@ -46,7 +46,7 @@ defmodule Explorer.Workers.RefreshBalanceTest do
insert(:from_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform("debit")
assert Repo.one(Debit).value == Decimal.new(20)
assert Repo.one(Debit).value == %Wei{value: Decimal.new(20)}
end
end
end

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

@ -8,7 +8,7 @@
<div class="address__item">
<dt class="address__item-key"><%= gettext "Balance" %></dt>
<dd class="address__item-value address__balance" title="<%= @address.hash %>" data-test="address_balance">
<%= balance(@address) %> <%= gettext "Ether" %>
<%= balance(@address) %>
</dd>
</div>
</dl>

@ -118,10 +118,10 @@
</div>
</td>
<td class="transactions__column transactions__column--value">
<%= value(transaction) %> <%= gettext "Ether" %>
<%= ExplorerWeb.TransactionView.value(transaction) %>
</td>
<td class="transactions__column transactions__column--value">
<%= fee(transaction) %> <%= gettext "Ether" %>
<%= ExplorerWeb.TransactionView.fee(transaction) %>
</td>
</tr>
<% end %>

@ -57,13 +57,7 @@
<%= block.gas_limit |> Cldr.Number.to_string! %>
</td>
<td class="blocks__column blocks__column--optional blocks__column--gas-price">
<%= block.transactions
|> Enum.map(fn(transaction) ->
Decimal.to_float(Decimal.div(Decimal.new(transaction.gas_price), Decimal.new(1_000_000_000)))
end)
|> Math.Enum.mean()
|> Kernel.||(0)
|> Cldr.Number.to_string! %> Gwei
<%= average_gas_price(block) %>
</td>
</tr>
<% end %>

@ -143,7 +143,7 @@
) %></div>
</td>
<td class="transactions__column transactions__column--value">
<%= value(transaction) %> <%= gettext "Ether" %>
<%= ExplorerWeb.TransactionView.value(transaction) %>
</td>
</tr>
<% end %>

@ -134,7 +134,7 @@
<%= transaction.block.timestamp |> Timex.from_now() %>
</td>
<td class="transactions__column transactions__column--value">
<%= value(transaction) %> <%= gettext "Ether" %>
<%= ExplorerWeb.TransactionView.value(transaction) %>
</td>
</tr>
<% end %>

@ -77,7 +77,7 @@
<% end %>
</td>
<td class="transactions__column transactions__column--value">
<%= value(transaction) %> <%= gettext "Ether" %>
<%= ExplorerWeb.TransactionView.value(transaction) %>
</td>
</tr>
<% end %>

@ -81,7 +81,7 @@
) %></div>
</td>
<td class="transactions__column transactions__column--value">
<%= value(transaction) %> <%= gettext "Ether" %>
<%= value(transaction) %>
</td>
</tr>
<% end %>

@ -41,7 +41,7 @@
</div>
<div class="transaction__item">
<dt class="transaction__item-key"><%= gettext "Value" %></dt>
<dd class="transaction__item-value"><%= value(@transaction) %> <%= gettext "Ether" %></dd>
<dd class="transaction__item-value"><%= value(@transaction) %></dd>
</div>
<div class="transaction__item">
<dt class="transaction__item-key"><%= gettext "From" %></dt>
@ -96,8 +96,8 @@
<div class="transaction__item">
<dt class="transaction__item-key"><%= gettext "Gas Price" %></dt>
<dd class="transaction__item-value">
<%= gas_price(@transaction, :wei) %> <%= gettext("Wei") %>
(<%= gas_price(@transaction, :gwei) %> <%= gettext "Gwei" %>)
<%= gas_price(@transaction, :wei) %>
(<%= gas_price(@transaction, :gwei) %>)
</dd>
</div>
<div class="transaction__item">

@ -42,7 +42,7 @@
to: address_path(@conn, :show, @conn.assigns.locale, transaction.to_address.hash),
class: "transaction-log__link") %>
</td>
<td><%= value(transaction) %></td>
<td><%= value(transaction, include_label: false) %></td>
<td><%= gas(transaction) %></td>
</tr>
</tgroup>

@ -3,8 +3,6 @@ defmodule ExplorerWeb.AddressTransactionView do
alias ExplorerWeb.TransactionView
defdelegate fee(transaction), to: TransactionView
def format_current_filter(filter) do
case filter do
"to" -> gettext("To")
@ -13,6 +11,5 @@ defmodule ExplorerWeb.AddressTransactionView do
end
end
defdelegate status(transacton), to: TransactionView
defdelegate value(transaction), to: TransactionView
defdelegate status(transaction), to: TransactionView
end

@ -1,16 +1,16 @@
defmodule ExplorerWeb.AddressView do
use ExplorerWeb, :view
alias Explorer.Chain
alias Explorer.Chain.Address
@dialyzer :no_match
def balance(address) do
address
|> Chain.balance(:ether)
|> case do
nil -> ""
ether -> Cldr.Number.to_string!(ether, fractional_digits: 18)
end
def balance(%Address{balance: nil}), do: ""
@doc """
Returns a formatted address balance and includes the unit.
"""
def balance(%Address{balance: balance}) do
format_wei_value(balance, :ether, fractional_digits: 18)
end
end

@ -6,7 +6,6 @@ defmodule ExplorerWeb.BlockTransactionView do
# Functions
defdelegate status(transacton), to: TransactionView
defdelegate value(transaction), to: TransactionView
defdelegate age(block), to: BlockView
defdelegate formatted_timestamp(block), to: BlockView
end

@ -1,7 +1,9 @@
defmodule ExplorerWeb.BlockView do
use ExplorerWeb, :view
alias Explorer.Chain.Block
import Math.Enum, only: [mean: 1]
alias Explorer.Chain.{Block, Wei}
@dialyzer :no_match
@ -14,4 +16,17 @@ defmodule ExplorerWeb.BlockView do
def formatted_timestamp(%Block{timestamp: timestamp}) do
Timex.format!(timestamp, "%b-%d-%Y %H:%M:%S %p %Z", :strftime)
end
def average_gas_price(%Block{transactions: transactions}) do
average =
transactions
|> Enum.map(&Decimal.to_float(Wei.to(&1.gas_price, :gwei)))
|> mean()
|> Kernel.||(0)
|> Cldr.Number.to_string!()
unit_text = gettext("Gwei")
"#{average} #{unit_text}"
end
end

@ -1,7 +1,3 @@
defmodule ExplorerWeb.ChainView do
use ExplorerWeb, :view
alias ExplorerWeb.TransactionView
defdelegate value(transaction), to: TransactionView
end

@ -23,6 +23,4 @@ defmodule ExplorerWeb.PendingTransactionView do
_ -> nil
end
end
defdelegate value(transaction), to: TransactionView
end

@ -3,7 +3,7 @@ defmodule ExplorerWeb.TransactionView do
alias Cldr.Number
alias Explorer.Chain
alias Explorer.Chain.{Block, InternalTransaction, Transaction}
alias Explorer.Chain.{Block, InternalTransaction, Transaction, Wei}
alias ExplorerWeb.BlockView
# Functions
@ -22,15 +22,16 @@ defmodule ExplorerWeb.TransactionView do
end
end
def fee(transaction) do
transaction
|> Chain.fee(:ether)
|> case do
@doc """
Calculates the transaction fee and returns a formatted display value.
"""
def fee(%Transaction{} = transaction) do
case Chain.fee(transaction, :wei) do
{:actual, actual} ->
Cldr.Number.to_string!(actual, fractional_digits: 18)
format_wei_value(Wei.from(actual, :wei), :ether, fractional_digits: 18)
{:maximum, maximum} ->
"<= " <> Cldr.Number.to_string!(maximum, fractional_digits: 18)
"<= " <> format_wei_value(Wei.from(maximum, :wei), :ether, fractional_digits: 18)
end
end
@ -56,14 +57,17 @@ defmodule ExplorerWeb.TransactionView do
end
end
def gas(%type{gas: gas}) when type in [InternalTransaction, Transaction] do
defguardp is_transaction_type(mod) when mod in [InternalTransaction, Transaction]
def gas(%type{gas: gas}) when is_transaction_type(type) do
Cldr.Number.to_string!(gas)
end
def gas_price(transaction, unit) do
transaction
|> Chain.gas_price(unit)
|> Cldr.Number.to_string!()
@doc """
Converts a transaction's gas price to a displayable value.
"""
def gas_price(%Transaction{gas_price: gas_price}, unit) when unit in ~w(wei gwei ether)a do
format_wei_value(gas_price, unit)
end
def last_seen(%Transaction{updated_at: updated_at}) do
@ -85,9 +89,15 @@ defmodule ExplorerWeb.TransactionView do
end
end
def value(transaction) do
transaction
|> Chain.value(:ether)
|> Cldr.Number.to_string!()
@doc """
Converts a transaction's Wei value to Ether and returns a formatted display value.
## Options
* `: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)
format_wei_value(value, :ether, include_unit_label: include_label?)
end
end

@ -0,0 +1,93 @@
defmodule ExplorerWeb.WeiHelpers do
@moduledoc """
Helper functions for interacting with `t:Explorer.Chain.Wei.t/0` values.
"""
import ExplorerWeb.Gettext
alias Explorer.Chain.Wei
@valid_units ~w(wei gwei ether)a
@type format_option :: {:fractional_digits, pos_integer()} | {:include_unit_label, boolean()}
@type format_options :: [format_option()]
@doc """
Converts a `t:Explorer.Wei.t/0` value to the specified unit including a
translated unit label.
## Supported Formatting Options
The third argument allows for keyword options to be passed for formatting the
converted number.
* `:fractional_digits` - Integer. Number of fractional digits to include
* `:include_unit_label` - Boolean (Defaults to `true`). Flag for if the unit
label should be included in the returned string
## Examples
iex> format_wei_value(%Wei{value: Decimal.new(1)}, :wei)
"1 Wei"
iex> format_wei_value(%Wei{value: Decimal.new(1, 10, 12)}, :gwei)
"10,000 Gwei"
iex> format_wei_value(%Wei{value: Decimal.new(1, 10, 21)}, :ether)
"10,000 POA"
# With formatting options
iex> format_wei_value(
...> %Wei{value: Decimal.new(1)},
...> :wei,
...> fractional_digits: 3
...> )
"1.000 Wei"
iex> format_wei_value(
...> %Wei{value: Decimal.new(10)},
...> :wei,
...> include_unit_label: false
...> )
"10"
"""
@spec format_wei_value(Wei.t(), Wei.unit(), format_options()) :: String.t()
def format_wei_value(%Wei{} = wei, unit, options \\ []) when unit in @valid_units do
number_format_options = build_number_format_options(options)
converted_value =
wei
|> Wei.to(unit)
|> Cldr.Number.to_string!(number_format_options)
if Keyword.get(options, :include_unit_label, true) do
display_unit = display_unit(unit)
"#{converted_value} #{display_unit}"
else
converted_value
end
end
defp build_number_format_options(options) do
Enum.reduce(options, [], fn option, formatted_options ->
case parse_number_format_option(option) do
nil -> formatted_options
{key, value} -> Keyword.put(formatted_options, key, value)
end
end)
end
defp display_unit(:wei), do: gettext("Wei")
defp display_unit(:gwei), do: gettext("Gwei")
defp display_unit(:ether), do: gettext("Ether")
defguardp is_fractional_digit(digits) when is_integer(digits) and digits > 0
defp parse_number_format_option({:fractional_digits, digits}) when is_fractional_digit(digits) do
{:fractional_digits, digits}
end
defp parse_number_format_option(_), do: nil
end

@ -171,7 +171,7 @@ msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:47
#: lib/explorer_web/templates/transaction/show.html.eex:26
#: lib/explorer_web/views/address_internal_transaction_view.ex:7
#: lib/explorer_web/views/address_transaction_view.ex:11
#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "From"
msgstr ""
@ -180,7 +180,7 @@ msgstr ""
msgid "Overview"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:84
#: lib/explorer_web/views/transaction_view.ex:88
msgid "Success"
msgstr ""
@ -194,7 +194,7 @@ msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:61
#: lib/explorer_web/templates/transaction/show.html.eex:27
#: lib/explorer_web/views/address_internal_transaction_view.ex:6
#: lib/explorer_web/views/address_transaction_view.ex:10
#: lib/explorer_web/views/address_transaction_view.ex:8
msgid "To"
msgstr ""
@ -241,9 +241,9 @@ msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:56
#: lib/explorer_web/templates/transaction/overview.html.eex:70
#: lib/explorer_web/views/transaction_view.ex:20
#: lib/explorer_web/views/transaction_view.ex:47
#: lib/explorer_web/views/transaction_view.ex:54
#: lib/explorer_web/views/transaction_view.ex:83
#: lib/explorer_web/views/transaction_view.ex:48
#: lib/explorer_web/views/transaction_view.ex:55
#: lib/explorer_web/views/transaction_view.ex:87
msgid "Pending"
msgstr ""
@ -306,11 +306,11 @@ msgstr ""
msgid "Next Page"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:81
#: lib/explorer_web/views/transaction_view.ex:85
msgid "Failed"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:82
#: lib/explorer_web/views/transaction_view.ex:86
msgid "Out of Gas"
msgstr ""
@ -329,19 +329,13 @@ msgstr ""
msgid "Showing #%{number}"
msgstr ""
#: lib/explorer_web/templates/address/overview.html.eex:11
#: lib/explorer_web/templates/address_transaction/index.html.eex:121
#: lib/explorer_web/templates/address_transaction/index.html.eex:124
#: lib/explorer_web/templates/block_transaction/index.html.eex:146
#: lib/explorer_web/templates/chain/show.html.eex:137
#: lib/explorer_web/templates/pending_transaction/index.html.eex:80
#: lib/explorer_web/templates/transaction/index.html.eex:84
#: lib/explorer_web/templates/transaction/overview.html.eex:44
#: lib/explorer_web/templates/transaction/show.html.eex:28
#: lib/explorer_web/views/wei_helpers.ex:84
msgid "Ether"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:100
#: lib/explorer_web/views/block_view.ex:28
#: lib/explorer_web/views/wei_helpers.ex:83
msgid "Gwei"
msgstr ""
@ -381,15 +375,15 @@ msgstr ""
msgid "Type"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:99
#: lib/explorer_web/templates/transaction/overview.html.eex:105
#: lib/explorer_web/views/wei_helpers.ex:82
msgid "Wei"
msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:28
#: lib/explorer_web/templates/address_transaction/index.html.eex:29
#: lib/explorer_web/views/address_internal_transaction_view.ex:8
#: lib/explorer_web/views/address_transaction_view.ex:12
#: lib/explorer_web/views/address_transaction_view.ex:10
msgid "All"
msgstr ""

@ -183,7 +183,7 @@ msgstr "Address"
#: lib/explorer_web/templates/transaction/overview.html.eex:47
#: lib/explorer_web/templates/transaction/show.html.eex:26
#: lib/explorer_web/views/address_internal_transaction_view.ex:7
#: lib/explorer_web/views/address_transaction_view.ex:11
#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "From"
msgstr "From"
@ -192,7 +192,7 @@ msgstr "From"
msgid "Overview"
msgstr "Overview"
#: lib/explorer_web/views/transaction_view.ex:84
#: lib/explorer_web/views/transaction_view.ex:88
msgid "Success"
msgstr "Success"
@ -206,7 +206,7 @@ msgstr "Success"
#: lib/explorer_web/templates/transaction/overview.html.eex:61
#: lib/explorer_web/templates/transaction/show.html.eex:27
#: lib/explorer_web/views/address_internal_transaction_view.ex:6
#: lib/explorer_web/views/address_transaction_view.ex:10
#: lib/explorer_web/views/address_transaction_view.ex:8
msgid "To"
msgstr "To"
@ -253,9 +253,9 @@ msgstr "Showing %{count} Transactions"
#: lib/explorer_web/templates/transaction/overview.html.eex:56
#: lib/explorer_web/templates/transaction/overview.html.eex:70
#: lib/explorer_web/views/transaction_view.ex:20
#: lib/explorer_web/views/transaction_view.ex:47
#: lib/explorer_web/views/transaction_view.ex:54
#: lib/explorer_web/views/transaction_view.ex:83
#: lib/explorer_web/views/transaction_view.ex:48
#: lib/explorer_web/views/transaction_view.ex:55
#: lib/explorer_web/views/transaction_view.ex:87
msgid "Pending"
msgstr "Pending"
@ -318,11 +318,11 @@ msgstr ""
msgid "Next Page"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:81
#: lib/explorer_web/views/transaction_view.ex:85
msgid "Failed"
msgstr ""
#: lib/explorer_web/views/transaction_view.ex:82
#: lib/explorer_web/views/transaction_view.ex:86
msgid "Out of Gas"
msgstr ""
@ -341,19 +341,13 @@ msgstr ""
msgid "Showing #%{number}"
msgstr ""
#: lib/explorer_web/templates/address/overview.html.eex:11
#: lib/explorer_web/templates/address_transaction/index.html.eex:121
#: lib/explorer_web/templates/address_transaction/index.html.eex:124
#: lib/explorer_web/templates/block_transaction/index.html.eex:146
#: lib/explorer_web/templates/chain/show.html.eex:137
#: lib/explorer_web/templates/pending_transaction/index.html.eex:80
#: lib/explorer_web/templates/transaction/index.html.eex:84
#: lib/explorer_web/templates/transaction/overview.html.eex:44
#: lib/explorer_web/templates/transaction/show.html.eex:28
#: lib/explorer_web/views/wei_helpers.ex:84
msgid "Ether"
msgstr "POA"
#: lib/explorer_web/templates/transaction/overview.html.eex:100
#: lib/explorer_web/views/block_view.ex:28
#: lib/explorer_web/views/wei_helpers.ex:83
msgid "Gwei"
msgstr ""
@ -393,15 +387,15 @@ msgstr ""
msgid "Type"
msgstr ""
#: lib/explorer_web/templates/transaction/overview.html.eex:99
#: lib/explorer_web/templates/transaction/overview.html.eex:105
#: lib/explorer_web/views/wei_helpers.ex:82
msgid "Wei"
msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:28
#: lib/explorer_web/templates/address_transaction/index.html.eex:29
#: lib/explorer_web/views/address_internal_transaction_view.ex:8
#: lib/explorer_web/views/address_transaction_view.ex:12
#: lib/explorer_web/views/address_transaction_view.ex:10
msgid "All"
msgstr ""

@ -1,60 +0,0 @@
defmodule ExplorerWeb.AddressTransactionViewTest do
use Explorer.DataCase
alias ExplorerWeb.AddressTransactionView
describe "fee/0" do
test "formats the fee for a successful transaction" do
insert(:block, number: 24)
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time
})
to_address = insert(:address, hash: "0xsleepypuppy")
from_address = insert(:address, hash: "0xilovefrogs")
transaction =
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"),
to_address_id: to_address.id,
from_address_id: from_address.id,
gas_price: Decimal.new(1_000_000_000.0)
)
|> with_block(block)
insert(:receipt, status: 1, gas_used: Decimal.new(435_334), transaction: transaction)
transaction =
transaction
|> Repo.preload([:receipt])
assert AddressTransactionView.fee(transaction) == "0.000,435,334,000,000,000"
end
test "fee returns max_gas for pending transaction" do
to_address = insert(:address, hash: "0xchadmuska")
from_address = insert(:address, hash: "0xtonyhawk")
transaction =
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"),
to_address_id: to_address.id,
from_address_id: from_address.id,
gas: Decimal.new(21000.0),
gas_price: Decimal.new(1_000_000_000.0)
)
|> Repo.preload([:to_address, :from_address, :receipt])
assert AddressTransactionView.fee(transaction) == "<= 0.000,021,000,000,000,000"
end
end
end

@ -0,0 +1,8 @@
defmodule ExplorerWeb.WeiHelpersTest do
use ExUnit.Case
# Needed for doctest
alias Explorer.Chain.Wei
doctest ExplorerWeb.WeiHelpers, import: true
end
Loading…
Cancel
Save