Add broadcast for token total supply

pull/6933/head
Nikita Pozdniakov 2 years ago
parent d83ee4ee21
commit 6c111614de
No known key found for this signature in database
GPG Key ID: F344106F9804FE5F
  1. 25
      apps/block_scout_web/assets/js/pages/token_counters.js
  2. 25
      apps/block_scout_web/lib/block_scout_web/channels/token_channel.ex
  3. 3
      apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex
  4. 2
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex
  5. 8
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  6. 1
      apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex
  7. 16
      apps/block_scout_web/lib/block_scout_web/templates/tokens/overview/_details.html.eex
  8. 2
      apps/explorer/lib/explorer/chain/events/publisher.ex
  9. 2
      apps/explorer/lib/explorer/chain/events/subscriber.ex
  10. 13
      apps/indexer/lib/indexer/fetcher/token_total_supply_on_demand.ex

@ -7,6 +7,7 @@ import '../app'
import { import {
openQrModal openQrModal
} from '../lib/modals' } from '../lib/modals'
import { subscribeChannel } from '../socket'
export const initialState = { export const initialState = {
channelDisconnected: false, channelDisconnected: false,
@ -26,6 +27,11 @@ export function reducer (state = initialState, action) {
tokenHolderCount: action.tokenHolderCount tokenHolderCount: action.tokenHolderCount
}) })
} }
case 'RECEIVED_NEW_TOTAL_SUPPLY': {
return Object.assign({}, state, {
totalSupply: action.msg.totalSupply
})
}
default: default:
return state return state
} }
@ -55,6 +61,16 @@ const elements = {
return $el.show() return $el.show()
} }
} }
},
'[data-selector="total-supply-row"]': {
render ($el, state) {
if (state.totalSupply) {
const value = $el.find('[data-selector="total-supply-value"]')
value.empty().append(state.totalSupply + ' ' + value[0].dataset.tokenSymbol)
state.totalSupply = null
return $el.removeClass('d-none')
}
}
} }
} }
@ -81,6 +97,15 @@ if ($tokenPage.length) {
function updateCounters () { function updateCounters () {
const store = createStore(reducer) const store = createStore(reducer)
connectElements({ store, elements }) connectElements({ store, elements })
const addressHash = $('[data-page="token-details"]')[0].dataset.pageAddressHash
const tokensChannel = subscribeChannel(`tokens:${addressHash}`)
tokensChannel.on('total_supply', (msg) => {
store.dispatch({
type: 'RECEIVED_NEW_TOTAL_SUPPLY',
msg: humps.camelizeKeys(msg)
})
})
loadCounters(store) loadCounters(store)
} }

@ -4,12 +4,13 @@ defmodule BlockScoutWeb.TokenChannel do
""" """
use BlockScoutWeb, :channel use BlockScoutWeb, :channel
alias BlockScoutWeb.{CurrencyHelpers, TokensView}
alias BlockScoutWeb.Tokens.TransferView alias BlockScoutWeb.Tokens.TransferView
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Phoenix.View alias Phoenix.View
intercept(["token_transfer"]) intercept(["token_transfer", "token_total_supply"])
{:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
@burn_address_hash burn_address_hash @burn_address_hash burn_address_hash
@ -48,4 +49,26 @@ defmodule BlockScoutWeb.TokenChannel do
{:noreply, socket} {:noreply, socket}
end end
def handle_out(
"token_total_supply",
%{token: %Explorer.Chain.Token{total_supply: total_supply}},
%Phoenix.Socket{handler: BlockScoutWeb.UserSocketV2} = socket
) do
push(socket, "total_supply", %{total_supply: to_string(total_supply)})
{:noreply, socket}
end
def handle_out("token_total_supply", %{token: token}, socket) do
push(socket, "total_supply", %{
total_supply:
if(TokensView.decimals?(token),
do: CurrencyHelpers.format_according_to_decimals(token.total_supply, token.decimals),
else: CurrencyHelpers.format_integer_to_currency(token.total_supply)
)
})
{:noreply, socket}
end
end end

@ -99,8 +99,7 @@ defmodule BlockScoutWeb.TransactionChannel do
internal_transactions = Chain.all_transaction_to_internal_transactions(transaction_hash) internal_transactions = Chain.all_transaction_to_internal_transactions(transaction_hash)
push(socket, "raw_trace", %{ push(socket, "raw_trace", %{
raw_trace: raw_trace: TransactionViewV2.render("raw_trace.json", %{internal_transactions: internal_transactions})
TransactionViewV2.render("raw_trace.json", %{internal_transactions: internal_transactions})
}) })
{:noreply, socket} {:noreply, socket}

@ -8,6 +8,7 @@ defmodule BlockScoutWeb.Tokens.HolderController do
alias BlockScoutWeb.Tokens.HolderView alias BlockScoutWeb.Tokens.HolderView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.Chain.Address alias Explorer.Chain.Address
alias Indexer.Fetcher.TokenTotalSupplyOnDemand
alias Phoenix.View alias Phoenix.View
import BlockScoutWeb.Chain, import BlockScoutWeb.Chain,
@ -70,6 +71,7 @@ defmodule BlockScoutWeb.Tokens.HolderController do
current_path: Controller.current_full_path(conn), current_path: Controller.current_full_path(conn),
token: Market.add_price(token), token: Market.add_price(token),
counters_path: token_path(conn, :token_counters, %{"id" => Address.checksum(address_hash)}), counters_path: token_path(conn, :token_counters, %{"id" => Address.checksum(address_hash)}),
token_total_supply_status: TokenTotalSupplyOnDemand.trigger_fetch(address_hash),
tags: get_address_tags(address_hash, current_user(conn)) tags: get_address_tags(address_hash, current_user(conn))
) )
else else

@ -213,6 +213,14 @@ defmodule BlockScoutWeb.Notifier do
Endpoint.broadcast("transactions:stats", "update", %{stats: stats}) Endpoint.broadcast("transactions:stats", "update", %{stats: stats})
end end
def handle_event(
{:chain_event, :token_total_supply, :on_demand,
[%Explorer.Chain.Token{contract_address_hash: contract_address_hash, total_supply: total_supply} = token]}
)
when not is_nil(total_supply) do
Endpoint.broadcast("tokens:#{to_string(contract_address_hash)}", "token_total_supply", %{token: token})
end
def handle_event(_), do: nil def handle_event(_), do: nil
def fetch_compiler_version(compiler) do def fetch_compiler_version(compiler) do

@ -28,6 +28,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do
Subscriber.to(:address_coin_balances, :on_demand) Subscriber.to(:address_coin_balances, :on_demand)
Subscriber.to(:address_token_balances, :on_demand) Subscriber.to(:address_token_balances, :on_demand)
Subscriber.to(:contract_verification_result, :on_demand) Subscriber.to(:contract_verification_result, :on_demand)
Subscriber.to(:token_total_supply, :on_demand)
# Does not come from the indexer # Does not come from the indexer
Subscriber.to(:exchange_rate) Subscriber.to(:exchange_rate)
Subscriber.to(:transaction_stats) Subscriber.to(:transaction_stats)

@ -62,13 +62,13 @@
</dd> </dd>
</dl> </dl>
<%= if total_supply?(@token) do %> <%= if total_supply?(@token) do %>
<dl class="row"> <dl class="row" data-selector="total-supply-row">
<dt class="col-sm-4 col-md-4 col-lg-3 text-muted"> <dt class="col-sm-4 col-md-4 col-lg-3 text-muted">
<%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html", <%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html",
text: gettext("The total amount of tokens issued") %> text: gettext("The total amount of tokens issued") %>
<%= gettext("Total supply") %> <%= gettext("Total supply") %>
</dt> </dt>
<dd class="col-sm-8 col-md-8 col-lg-9"> <dd class="col-sm-8 col-md-8 col-lg-9" data-selector="total-supply-value" data-token-symbol="<%= @token.symbol %>">
<%= if decimals?(@token) do %> <%= if decimals?(@token) do %>
<%= format_according_to_decimals(@token.total_supply, @token.decimals) %> <%= format_according_to_decimals(@token.total_supply, @token.decimals) %>
<% else %> <% else %>
@ -76,6 +76,18 @@
<% end %> <%= @token.symbol %> <% end %> <%= @token.symbol %>
</dd> </dd>
</dl> </dl>
<% else %>
<dl class="row d-none" data-selector="total-supply-row">
<dt class="col-sm-4 col-md-4 col-lg-3 text-muted">
<%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html",
text: gettext("The total amount of tokens issued") %>
<%= gettext("Total supply") %>
</dt>
<dd class="col-sm-8 col-md-8 col-lg-9" data-selector="total-supply-value" data-token-symbol="<%= @token.symbol %>">
</dd>
</dl>
<% end %>
<%= if total_supply?(@token) do %>
<%= if @token.usd_value do %> <%= if @token.usd_value do %>
<dl class="row"> <dl class="row">
<dt class="col-sm-4 col-md-4 col-lg-3 text-muted"> <dt class="col-sm-4 col-md-4 col-lg-3 text-muted">

@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Publisher do
Publishes events related to the Chain context. Publishes events related to the Chain context.
""" """
@allowed_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result)a @allowed_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply)a
def broadcast(_data, false), do: :ok def broadcast(_data, false), do: :ok

@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Subscriber do
Subscribes to events related to the Chain context. Subscribes to events related to the Chain context.
""" """
@allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result)a @allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply)a
@allowed_broadcast_types ~w(catchup realtime on_demand contract_verification_result)a @allowed_broadcast_types ~w(catchup realtime on_demand contract_verification_result)a

@ -9,6 +9,7 @@ defmodule Indexer.Fetcher.TokenTotalSupplyOnDemand do
alias Explorer.{Chain, Repo} alias Explorer.{Chain, Repo}
alias Explorer.Chain.{Address, Token} alias Explorer.Chain.{Address, Token}
alias Explorer.Chain.Cache.BlockNumber alias Explorer.Chain.Cache.BlockNumber
alias Explorer.Chain.Events.Publisher
alias Explorer.Token.MetadataRetriever alias Explorer.Token.MetadataRetriever
@ttl_in_blocks 1 @ttl_in_blocks 1
@ -33,14 +34,14 @@ defmodule Indexer.Fetcher.TokenTotalSupplyOnDemand do
@impl true @impl true
def handle_cast({:fetch_and_update, address}, state) do def handle_cast({:fetch_and_update, address}, state) do
do_trigger_fetch(address) do_fetch(address)
{:noreply, state} {:noreply, state}
end end
## Implementation ## Implementation
defp do_trigger_fetch(address) when not is_nil(address) do defp do_fetch(address) when not is_nil(address) do
token = token =
Token Token
|> Repo.get_by(contract_address_hash: address) |> Repo.get_by(contract_address_hash: address)
@ -54,12 +55,10 @@ defmodule Indexer.Fetcher.TokenTotalSupplyOnDemand do
token_address_hash token_address_hash
|> MetadataRetriever.get_total_supply_of() |> MetadataRetriever.get_total_supply_of()
token = {:ok, token} =
Token Chain.update_token(token, Map.put(token_params, :total_supply_updated_at_block, BlockNumber.get_max()))
|> Repo.get_by(contract_address_hash: address)
|> Repo.preload([:contract_address])
{:ok, _} = Chain.update_token(token, Map.put(token_params, :total_supply_updated_at_block, BlockNumber.get_max())) Publisher.broadcast(%{token_total_supply: [token]}, :on_demand)
:ok :ok
end end
end end

Loading…
Cancel
Save