parent
1414a94973
commit
95de1ebcb0
@ -0,0 +1,189 @@ |
||||
defmodule Explorer.Chain.TokenTransferTest do |
||||
use Explorer.DataCase |
||||
|
||||
import Explorer.Factory |
||||
|
||||
alias Explorer.PagingOptions |
||||
alias Explorer.Chain.TokenTransfer |
||||
|
||||
doctest Explorer.Chain.TokenTransfer |
||||
|
||||
describe "fetch_token_transfers/2" do |
||||
test "returns token transfers for the given address" do |
||||
token_contract_address = insert(:contract_address) |
||||
|
||||
transaction = |
||||
:transaction |
||||
|> insert() |
||||
|> with_block() |
||||
|
||||
token = insert(:token, contract_address: token_contract_address) |
||||
|
||||
token_transfer = |
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
another_transfer = |
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: build(:address), |
||||
token: token |
||||
) |
||||
|
||||
transfers_ids = |
||||
token_contract_address.hash |
||||
|> TokenTransfer.fetch_token_transfers_from_token_hash([]) |
||||
|> Enum.map(& &1.id) |
||||
|
||||
assert transfers_ids == [another_transfer.id, token_transfer.id] |
||||
end |
||||
|
||||
test "when there isn't token transfers won't show anything" do |
||||
token_contract_address = insert(:contract_address) |
||||
|
||||
insert(:token, contract_address: token_contract_address) |
||||
|
||||
transfers_ids = |
||||
token_contract_address.hash |
||||
|> TokenTransfer.fetch_token_transfers_from_token_hash([]) |
||||
|> Enum.map(& &1.id) |
||||
|
||||
assert transfers_ids == [] |
||||
end |
||||
|
||||
test "token transfers can be paginated" do |
||||
token_contract_address = insert(:contract_address) |
||||
|
||||
transaction = |
||||
:transaction |
||||
|> insert() |
||||
|> with_block() |
||||
|
||||
token = insert(:token) |
||||
|
||||
second_page = |
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
first_page = |
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
paging_options = %PagingOptions{key: first_page.inserted_at, page_size: 1} |
||||
|
||||
token_transfers_ids_paginated = |
||||
TokenTransfer.fetch_token_transfers_from_token_hash( |
||||
token_contract_address.hash, |
||||
paging_options: paging_options |
||||
) |
||||
|> Enum.map(& &1.id) |
||||
|
||||
assert token_transfers_ids_paginated == [second_page.id] |
||||
end |
||||
end |
||||
|
||||
describe "count_token_transfers/1" do |
||||
test "counts how many token transfers a token has" do |
||||
token_contract_address = insert(:contract_address) |
||||
|
||||
transaction = |
||||
:transaction |
||||
|> insert() |
||||
|> with_block() |
||||
|
||||
token = insert(:token) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
to_address: build(:address), |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address, |
||||
token: token |
||||
) |
||||
|
||||
assert TokenTransfer.count_token_transfers_from_token_hash(token_contract_address.hash) == 2 |
||||
end |
||||
end |
||||
|
||||
describe "count_addresses_in_transfers/1" do |
||||
test "counts how many unique addresses that appeared at `to` or `from`" do |
||||
token_contract_address = insert(:contract_address) |
||||
|
||||
transaction = |
||||
:transaction |
||||
|> insert() |
||||
|> with_block() |
||||
|
||||
john_address = insert(:address) |
||||
jane_address = insert(:address) |
||||
bob_address = insert(:address) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
from_address: jane_address, |
||||
to_address: john_address, |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address |
||||
) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
from_address: john_address, |
||||
to_address: jane_address, |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address |
||||
) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
from_address: bob_address, |
||||
to_address: jane_address, |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address |
||||
) |
||||
|
||||
insert( |
||||
:token_transfer, |
||||
from_address: jane_address, |
||||
to_address: bob_address, |
||||
transaction: transaction, |
||||
token_contract_address: token_contract_address |
||||
) |
||||
|
||||
assert TokenTransfer.count_addresses_in_token_transfers_from_token_hash(token_contract_address.hash) == 3 |
||||
end |
||||
end |
||||
end |
@ -1,10 +1,31 @@ |
||||
defmodule ExplorerWeb.TokenController do |
||||
use ExplorerWeb, :controller |
||||
|
||||
def show(conn, %{"id" => id, "locale" => locale}) do |
||||
alias Explorer.Chain |
||||
|
||||
import ExplorerWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3] |
||||
|
||||
def show(conn, %{"id" => address_hash_string} = params) do |
||||
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), |
||||
{:ok, token} <- Chain.token_from_address_hash(address_hash), |
||||
token_transfers <- Chain.fetch_token_transfers_from_token_hash(address_hash, paging_options(params)) do |
||||
{token_transfers_paginated, next_page} = split_list_by_page(token_transfers) |
||||
|
||||
render( |
||||
conn, |
||||
"show.html" |
||||
"show.html", |
||||
transfers: token_transfers_paginated, |
||||
token: token, |
||||
total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash), |
||||
total_address_in_token_transfers: Chain.count_addresses_in_token_transfers_from_token_hash(address_hash), |
||||
next_page_params: next_page_params(next_page, token_transfers_paginated, params) |
||||
) |
||||
else |
||||
:error -> |
||||
not_found(conn) |
||||
|
||||
{:error, :not_found} -> |
||||
not_found(conn) |
||||
end |
||||
end |
||||
end |
||||
|
@ -0,0 +1,48 @@ |
||||
<div class="tile tile-type-token fade-in mb-10"> |
||||
<div class="row"> |
||||
<div class="pl-5 col-md-2 d-flex flex-column align-items-left justify-content-start justify-content-lg-center"> |
||||
<span class="tile-label"><%= gettext "Token Transfer" %></span> |
||||
</div> |
||||
|
||||
<div class="col-md-7 col-lg-8 d-flex flex-column"> |
||||
<p class="tile-title text-truncate"> |
||||
<%= render ExplorerWeb.TransactionView, "_link.html", locale: @locale, transaction_hash: @transfer.transaction_hash %> |
||||
</p> |
||||
<span> |
||||
<%= render ExplorerWeb.AddressView, |
||||
"_link.html", |
||||
address_hash: to_string(@transfer.from_address_hash), |
||||
contract: ExplorerWeb.AddressView.contract?(@transfer.from_address), |
||||
locale: @locale %> |
||||
|
||||
→ |
||||
|
||||
<%= render ExplorerWeb.AddressView, |
||||
"_link.html", |
||||
address_hash: to_string(@transfer.to_address_hash), |
||||
contract: ExplorerWeb.AddressView.contract?(@transfer.to_address), |
||||
locale: @locale %> |
||||
</span> |
||||
|
||||
<span> |
||||
<span> |
||||
<%= token_transfer_amount(@transfer) %> <%= @transfer.token.symbol %></span> |
||||
</span> |
||||
</div> |
||||
|
||||
<div class="p-4 col-md-2 col-lg-2 d-flex flex-row flex-md-column justify-content-start align-items-end text-md-right"> |
||||
<span class="ml-1 mr-sm-0 text-muted" data-from-now="<%= @transfer.transaction.block.timestamp %>"></span> |
||||
|
||||
<span class="ml-2"> |
||||
<%= link( |
||||
gettext( |
||||
"Block #%{number}", |
||||
number: @transfer.transaction.block_number |
||||
), |
||||
class: "mr-2 mr-sm-0 text-muted", |
||||
to: block_path(ExplorerWeb.Endpoint, :show, @locale, @transfer.transaction.block_number) |
||||
) %> |
||||
</span> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -1,3 +1,9 @@ |
||||
defmodule ExplorerWeb.TokenView do |
||||
use ExplorerWeb, :view |
||||
|
||||
def decimals?(nil), do: false |
||||
def decimals?(_), do: true |
||||
|
||||
def token_name?(nil), do: false |
||||
def token_name?(_), do: true |
||||
end |
||||
|
Loading…
Reference in new issue