Merge pull request #4067 from blockscout/vb-display-lp-tokens-usd-value-in-dropdown

Display LP tokens USD value and custom metadata in tokens dropdown at address page
pull/4127/head
Victor Baranov 4 years ago committed by GitHub
commit b766aad555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex
  3. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex
  4. 24
      apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex
  5. 4
      apps/block_scout_web/lib/block_scout_web/views/address_token_balance_view.ex
  6. 32
      apps/block_scout_web/test/block_scout_web/views/address_token_balance_view_test.exs
  7. 2
      apps/explorer/lib/explorer/chain.ex
  8. 13
      apps/explorer/lib/explorer/chain/address/current_token_balance.ex
  9. 10
      apps/explorer/lib/explorer/market/market.ex
  10. 4
      apps/explorer/test/explorer/chain/address/current_token_balance_test.exs
  11. 2
      apps/explorer/test/explorer/chain_test.exs
  12. 4
      apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex

@ -1,6 +1,7 @@
## Current ## Current
### Features ### Features
- [#4067](https://github.com/blockscout/blockscout/pull/4067) - Display LP tokens USD value and custom metadata in tokens dropdown at address page
### Fixes ### Fixes
- [#4038](https://github.com/blockscout/blockscout/pull/4038) - Add clause for abi_decode_address_output/1 when is_nil(address) - [#4038](https://github.com/blockscout/blockscout/pull/4038) - Add clause for abi_decode_address_output/1 when is_nil(address)

@ -26,12 +26,12 @@ defmodule BlockScoutWeb.AddressTokenBalanceController do
token_balances_except_bridged = token_balances_except_bridged =
token_balances token_balances
|> Enum.filter(fn token_balance -> !token_balance.token.bridged end) |> Enum.filter(fn {token_balance, _} -> !token_balance.token.bridged end)
circles_total_balance = circles_total_balance =
if Enum.count(circles_addresses_list) > 0 do if Enum.count(circles_addresses_list) > 0 do
token_balances_except_bridged token_balances_except_bridged
|> Enum.reduce(Decimal.new(0), fn token_balance, acc_balance -> |> Enum.reduce(Decimal.new(0), fn {token_balance, _}, acc_balance ->
{:ok, token_address} = Chain.hash_to_address(token_balance.address_hash) {:ok, token_address} = Chain.hash_to_address(token_balance.address_hash)
from_address = from_address_hash(token_address) from_address = from_address_hash(token_address)

@ -36,7 +36,7 @@
placeholder: gettext("Search tokens") placeholder: gettext("Search tokens")
) %> ) %>
</div> </div>
<%= if Enum.any?(@token_balances, & &1.token.type == "ERC-721") do %> <%= if Enum.any?(@token_balances, fn {token_balance, _} -> token_balance.token.type == "ERC-721" end) do %>
<%= render( <%= render(
"_tokens.html", "_tokens.html",
conn: @conn, conn: @conn,
@ -45,7 +45,7 @@
) %> ) %>
<% end %> <% end %>
<%= if Enum.any?(@token_balances, & &1.token.type == "ERC-20") do %> <%= if Enum.any?(@token_balances, fn {token_balance, _} -> token_balance.token.type == "ERC-20" end) do %>
<%= render( <%= render(
"_tokens.html", "_tokens.html",
conn: @conn, conn: @conn,

@ -3,7 +3,7 @@
<%= @type %> (<span data-number-of-tokens-by-type="<%= @type %>"><%= Enum.count(@token_balances)%></span>) <%= @type %> (<span data-number-of-tokens-by-type="<%= @type %>"><%= Enum.count(@token_balances)%></span>)
</h6> </h6>
<%= for token_balance <- sort_by_usd_value_and_name(@token_balances) do %> <%= for {token_balance, bridged_token} <- sort_by_usd_value_and_name(@token_balances) do %>
<div <div
class="border-bottom" class="border-bottom"
data-dropdown-token-balance-test data-dropdown-token-balance-test
@ -15,15 +15,27 @@
class: "dropdown-item" class: "dropdown-item"
) do %> ) do %>
<div class="row"> <div class="row">
<p class="mb-0 col-md-6"><%= token_name(token_balance.token) %></p> <p class="mb-0 col-md-6"><%= token_name(token_balance.token) %>
<%= if token_balance.token.usd_value do %> <%= if bridged_token && bridged_token.custom_metadata do %>
<%= "(" <> bridged_token.custom_metadata <> ")" %>
<% end %>
</p>
<%= if bridged_token && bridged_token.lp_token && bridged_token.custom_cap do %>
<% lp_token_balance_usd = token_balance.value |> Decimal.div(token_balance.token.total_supply) |> Decimal.mult(bridged_token.custom_cap) |> Decimal.round(4) %>
<p class="mb-0 col-md-6 text-right"> <p class="mb-0 col-md-6 text-right">
<span data-selector="token-balance-usd" data-usd-value="<%= Chain.balance_in_usd(token_balance) %>"></span> <span data-selector="token-balance-usd" data-usd-value="<%= lp_token_balance_usd %>"></span>
</p> </p>
<% else %>
<%= if token_balance.token.usd_value do %>
<p class="mb-0 col-md-6 text-right">
<span data-selector="token-balance-usd" data-usd-value="<%= Chain.balance_in_usd(token_balance) %>"></span>
</p>
<% end %>
<% end %> <% end %>
</div> </div>
<div class="row"> <div class="row">
<p class="mb-0 col-md-6"> <% col_md = if token_balance.token.usd_value, do: "col-md-6", else: "col-md-12" %>
<p class="mb-0 <%= col_md %> ">
<%= format_according_to_decimals(token_balance.value, token_balance.token.decimals) %> <%= token_balance.token.symbol %> <%= format_according_to_decimals(token_balance.value, token_balance.token.decimals) %> <%= token_balance.token.symbol %>
</p> </p>
<%= if token_balance.token.usd_value do %> <%= if token_balance.token.usd_value do %>
@ -35,4 +47,4 @@
<% end %> <% end %>
</div> </div>
<% end %> <% end %>
</div> </div>

@ -9,7 +9,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceView do
end end
def filter_by_type(token_balances, type) do def filter_by_type(token_balances, type) do
Enum.filter(token_balances, &(&1.token.type == type)) Enum.filter(token_balances, fn {token_balance, _} -> token_balance.token.type == type end)
end end
@doc """ @doc """
@ -27,7 +27,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceView do
""" """
def sort_by_usd_value_and_name(token_balances) do def sort_by_usd_value_and_name(token_balances) do
token_balances token_balances
|> Enum.sort(fn token_balance1, token_balance2 -> |> Enum.sort(fn {token_balance1, _}, {token_balance2, _} ->
usd_value1 = token_balance1.token.usd_value usd_value1 = token_balance1.token.usd_value
usd_value2 = token_balance2.token.usd_value usd_value2 = token_balance2.token.usd_value

@ -20,9 +20,9 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do
token_balance_a = build(:token_balance, token: build(:token, type: "ERC-20")) token_balance_a = build(:token_balance, token: build(:token, type: "ERC-20"))
token_balance_b = build(:token_balance, token: build(:token, type: "ERC-721")) token_balance_b = build(:token_balance, token: build(:token, type: "ERC-721"))
token_balances = [token_balance_a, token_balance_b] token_balances = [{token_balance_a, %{}}, {token_balance_b, %{}}]
assert AddressTokenBalanceView.filter_by_type(token_balances, "ERC-20") == [token_balance_a] assert AddressTokenBalanceView.filter_by_type(token_balances, "ERC-20") == [{token_balance_a, %{}}]
end end
end end
@ -116,23 +116,23 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do
) )
token_balances = [ token_balances = [
token_balance_a, {token_balance_a, %{}},
token_balance_b, {token_balance_b, %{}},
token_balance_c, {token_balance_c, %{}},
token_balance_d, {token_balance_d, %{}},
token_balance_e, {token_balance_e, %{}},
token_balance_f, {token_balance_f, %{}},
token_balance_g {token_balance_g, %{}}
] ]
expected = [ expected = [
token_balance_b, {token_balance_b, %{}},
token_balance_a, {token_balance_a, %{}},
token_balance_c, {token_balance_c, %{}},
token_balance_d, {token_balance_d, %{}},
token_balance_g, {token_balance_g, %{}},
token_balance_e, {token_balance_e, %{}},
token_balance_f {token_balance_f, %{}}
] ]
assert AddressTokenBalanceView.sort_by_usd_value_and_name(token_balances) == expected assert AddressTokenBalanceView.sort_by_usd_value_and_name(token_balances) == expected

@ -2085,7 +2085,7 @@ defmodule Explorer.Chain do
def address_tokens_usd_sum(token_balances) do def address_tokens_usd_sum(token_balances) do
token_balances token_balances
|> Enum.reduce(Decimal.new(0), fn token_balance, acc -> |> Enum.reduce(Decimal.new(0), fn {token_balance, _}, acc ->
if token_balance.value && token_balance.token.usd_value do if token_balance.value && token_balance.token.usd_value do
Decimal.add(acc, balance_in_usd(token_balance)) Decimal.add(acc, balance_in_usd(token_balance))
else else

@ -12,7 +12,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
import Ecto.Query, only: [from: 2, limit: 2, offset: 2, order_by: 3, preload: 2, where: 3] import Ecto.Query, only: [from: 2, limit: 2, offset: 2, order_by: 3, preload: 2, where: 3]
alias Explorer.{Chain, PagingOptions} alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.{Address, Block, Hash, Token} alias Explorer.Chain.{Address, Block, BridgedToken, Hash, Token}
@default_paging_options %PagingOptions{page_size: 50} @default_paging_options %PagingOptions{page_size: 50}
@ -101,10 +101,13 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
""" """
def last_token_balances(address_hash) do def last_token_balances(address_hash) do
from( from(
tb in __MODULE__, ctb in __MODULE__,
where: tb.address_hash == ^address_hash, where: ctb.address_hash == ^address_hash,
where: tb.value > 0, where: ctb.value > 0,
preload: :token left_join: bt in BridgedToken,
on: ctb.token_contract_address_hash == bt.home_token_contract_address_hash,
preload: :token,
select: {ctb, bt}
) )
end end

@ -82,7 +82,15 @@ defmodule Explorer.Market do
end end
def add_price(tokens) when is_list(tokens) do def add_price(tokens) when is_list(tokens) do
Enum.map(tokens, &add_price/1) Enum.map(tokens, fn item ->
case item do
{token_balance, bridged_token} ->
{add_price(token_balance), bridged_token}
token_balance ->
add_price(token_balance)
end
end)
end end
defp mainnet_bridged_token?(token) do defp mainnet_bridged_token?(token) do

@ -157,7 +157,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalanceTest do
address.hash address.hash
|> CurrentTokenBalance.last_token_balances() |> CurrentTokenBalance.last_token_balances()
|> Repo.all() |> Repo.all()
|> Enum.map(& &1.address_hash) |> Enum.map(fn {token_balance, _} -> token_balance.address_hash end)
assert token_balances == [current_token_balance.address_hash] assert token_balances == [current_token_balance.address_hash]
end end
@ -195,7 +195,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalanceTest do
address.hash address.hash
|> CurrentTokenBalance.last_token_balances() |> CurrentTokenBalance.last_token_balances()
|> Repo.all() |> Repo.all()
|> Enum.map(& &1.address_hash) |> Enum.map(fn {token_balance, _} -> token_balance.address_hash end)
assert token_balances == [current_token_balance_a.address_hash] assert token_balances == [current_token_balance_a.address_hash]
end end

@ -4506,7 +4506,7 @@ defmodule Explorer.ChainTest do
token_balances = token_balances =
address.hash address.hash
|> Chain.fetch_last_token_balances() |> Chain.fetch_last_token_balances()
|> Enum.map(& &1.address_hash) |> Enum.map(fn {token_balance, _} -> token_balance.address_hash end)
assert token_balances == [current_token_balance.address_hash] assert token_balances == [current_token_balance.address_hash]
end end

@ -34,7 +34,7 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
when not is_nil(address_hash) do when not is_nil(address_hash) do
stale_current_token_balances = stale_current_token_balances =
current_token_balances current_token_balances
|> Enum.filter(fn current_token_balance -> current_token_balance.block_number < stale_balance_window end) |> Enum.filter(fn {current_token_balance, _} -> current_token_balance.block_number < stale_balance_window end)
if Enum.count(stale_current_token_balances) > 0 do if Enum.count(stale_current_token_balances) > 0 do
fetch_and_update(latest_block_number, address_hash, stale_current_token_balances) fetch_and_update(latest_block_number, address_hash, stale_current_token_balances)
@ -48,7 +48,7 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
defp fetch_and_update(block_number, address_hash, stale_current_token_balances) do defp fetch_and_update(block_number, address_hash, stale_current_token_balances) do
current_token_balances_update_params = current_token_balances_update_params =
stale_current_token_balances stale_current_token_balances
|> Enum.map(fn stale_current_token_balance -> |> Enum.map(fn {stale_current_token_balance, _} ->
stale_current_token_balances_to_fetch = [ stale_current_token_balances_to_fetch = [
%{ %{
token_contract_address_hash: token_contract_address_hash:

Loading…
Cancel
Save