Skip to content

Commit

Permalink
Merge pull request #130 from poanetwork/account-page-revised-transact…
Browse files Browse the repository at this point in the history
…ions-list-#14

Account page revised transactions list #14
  • Loading branch information
jimmay5469 committed Apr 19, 2018
2 parents fa2ab3b + 9d3734e commit a275393
Show file tree
Hide file tree
Showing 33 changed files with 1,732 additions and 1,394 deletions.
138 changes: 93 additions & 45 deletions apps/explorer/lib/explorer/chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Explorer.Chain do
The chain context.
"""

import Ecto.Query, only: [from: 2, order_by: 2, preload: 2, where: 2, where: 3]
import Ecto.Query, only: [from: 2, or_where: 3, order_by: 2, preload: 2, where: 2]

alias Explorer.Chain.{
Address,
Expand Down Expand Up @@ -42,11 +42,48 @@ defmodule Explorer.Chain do
"""
@type pagination :: map()

@typep direction_option :: :to | :from
@typep necessity_by_association_option :: {:necessity_by_association, necessity_by_association}
@typep pagination_option :: {:pagination, pagination}

# Functions

@doc """
`t:Explorer.Chain.Transaction/0`s from `address`.
## Options
* `:direction` - if specified, will filter transactions by address type. If `:to` is specified, only transactions
where the "to" address matches will be returned. Likewise, if `:from` is specified, only transactions where the
"from" address matches will be returned. If :direction is omitted, transactions either to or from the address
will be returned.
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Transaction.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Transaction.t/0` will not be included in the page `entries`.
* `:pagination` - pagination params to pass to scrivener.
"""
@spec address_to_transactions(Address.t(), [
direction_option | necessity_by_association_option | pagination_option
]) :: %Scrivener.Page{entries: [Transaction.t()]}
def address_to_transactions(address = %Address{}, options \\ [])
when is_list(options) do
address_id_to_transactions(address.id, options)
end

@doc """
The `t:Explorer.Chain.Address.t/0` `balance` in `unit`.
"""
@spec balance(Address.t(), :wei) :: Wei.t() | nil
@spec balance(Address.t(), :gwei) :: Wei.gwei() | nil
@spec balance(Address.t(), :ether) :: Wei.ether() | nil
def balance(%Address{balance: balance}, unit) do
case balance do
nil -> nil
_ -> Wei.to(balance, unit)
end
end

@doc """
Finds all `t:Explorer.Chain.Transaction.t/0` in the `t:Explorer.Chain.Block.t/0`.
Expand Down Expand Up @@ -155,22 +192,48 @@ defmodule Explorer.Chain do
end

@doc """
`t:Explorer.Chain.Transaction/0`s from `address`.
The fee a `transaction` paid for the `t:Explorer.Transaction.t/0` `gas`
## Options
If the transaction is pending, then the fee will be a range of `unit`
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Transaction.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Transaction.t/0` will not be included in the page `entries`.
* `:pagination` - pagination params to pass to scrivener.
iex> Explorer.Chain.fee(
...> %Explorer.Chain.Transaction{gas: Decimal.new(3), gas_price: Decimal.new(2), receipt: nil},
...> :wei
...> )
{:maximum, Decimal.new(6)}
If the transaction has been confirmed in block, then the fee will be the actual fee paid in `unit` for the `gas_used`
in the `receipt`.
iex> Explorer.Chain.fee(
...> %Explorer.Chain.Transaction{
...> gas: Decimal.new(3),
...> gas_price: Decimal.new(2),
...> receipt: Explorer.Chain.Receipt{gas_used: Decimal.new(2)}
...> },
...> :wei
...> )
{:actual, Decimal.new(4)}
"""
@spec from_address_to_transactions(Address.t(), [
necessity_by_association_option | pagination_option
]) :: %Scrivener.Page{entries: [Transaction.t()]}
def from_address_to_transactions(address = %Address{}, options \\ [])
when is_list(options) do
address_to_transactions(address, Keyword.put(options, :direction, :from))
@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)
|> Wei.to(unit)

{:maximum, fee}
end

@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)
|> Wei.to(unit)

{:actual, fee}
end

@doc """
Expand Down Expand Up @@ -335,24 +398,6 @@ defmodule Explorer.Chain do
end
end

@doc """
`t:Explorer.Chain.Transaction/0`s to `address`.
## Options
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Transaction.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Transaction.t/0` will not be included in the page `entries`.
* `:pagination` - pagination params to pass to scrivener.
"""
@spec to_address_to_transactions(Address.t(), [
necessity_by_association_option | pagination_option
]) :: %Scrivener.Page{entries: [Transaction.t()]}
def to_address_to_transactions(address = %Address{}, options \\ []) when is_list(options) do
address_to_transactions(address, Keyword.put(options, :direction, :to))
end

@doc """
Count of `t:Explorer.Chain.Transaction.t/0`.
Expand Down Expand Up @@ -499,30 +544,23 @@ defmodule Explorer.Chain do

defp address_id_to_transactions(address_id, named_arguments)
when is_integer(address_id) and is_list(named_arguments) do
field =
case Keyword.fetch!(named_arguments, :direction) do
:to -> :to_address_id
:from -> :from_address_id
address_fields =
case Keyword.get(named_arguments, :direction) do
:to -> [:to_address_id]
:from -> [:from_address_id]
nil -> [:to_address_id, :from_address_id]
end

necessity_by_association = Keyword.get(named_arguments, :necessity_by_association, %{})
pagination = Keyword.get(named_arguments, :pagination, %{})

Transaction
|> join_associations(necessity_by_association)
|> chronologically()
|> where([t], field(t, ^field) == ^address_id)
|> reverse_chronologically()
|> where_address_fields_match(address_fields, address_id)
|> Repo.paginate(pagination)
end

defp address_to_transactions(%Address{id: address_id}, options) when is_list(options) do
address_id_to_transactions(address_id, options)
end

defp chronologically(query) do
from(q in query, order_by: [desc: q.inserted_at, desc: q.id])
end

defp for_parent_transaction(query, hash) when is_binary(hash) do
from(
child in query,
Expand Down Expand Up @@ -556,6 +594,10 @@ defmodule Explorer.Chain do
)
end

defp reverse_chronologically(query) do
from(q in query, order_by: [desc: q.inserted_at, desc: q.id])
end

defp transaction_hash_to_logs(transaction_hash, options)
when is_binary(transaction_hash) and is_list(options) do
lower_transaction_hash = String.downcase(transaction_hash)
Expand All @@ -575,6 +617,12 @@ defmodule Explorer.Chain do
|> Repo.paginate(pagination)
end

defp where_address_fields_match(query, address_fields, address_id) do
Enum.reduce(address_fields, query, fn field, query ->
or_where(query, [t], field(t, ^field) == ^address_id)
end)
end

defp where_hash(query, hash) do
from(
q in query,
Expand Down

0 comments on commit a275393

Please sign in to comment.