From 0785ef8786f9c6c7d3eb94df639eb89fcff87a90 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Fri, 20 Nov 2020 20:17:16 +0300 Subject: [PATCH 1/3] Address tokens USD value sum --- .../address_token_balance_controller.ex | 4 +- .../controllers/tokens/holder_controller.ex | 6 +- .../_token_balances.html.eex | 3 + .../address_token_balance/_tokens.html.eex | 2 +- .../views/address_token_balance_view.ex | 18 +-- apps/block_scout_web/priv/gettext/default.pot | 4 +- .../priv/gettext/en/LC_MESSAGES/default.po | 4 +- .../views/address_token_balance_view_test.exs | 7 +- apps/explorer/config/config.exs | 11 ++ apps/explorer/lib/explorer/application.ex | 1 + apps/explorer/lib/explorer/chain.ex | 25 ++++ .../lib/explorer/chain/currency_helpers.ex | 12 ++ .../counters/address_tokens_usd_sum.ex | 112 ++++++++++++++++++ 13 files changed, 185 insertions(+), 24 deletions(-) create mode 100644 apps/explorer/lib/explorer/chain/currency_helpers.ex create mode 100644 apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex index 548b92b20d..42a78fb01d 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex @@ -17,13 +17,13 @@ defmodule BlockScoutWeb.AddressTokenBalanceController do conn |> put_status(200) |> put_layout(false) - |> render("_token_balances.html", token_balances: token_balances) + |> render("_token_balances.html", address_hash: address_hash, token_balances: token_balances) _ -> conn |> put_status(200) |> put_layout(false) - |> render("_token_balances.html", token_balances: []) + |> render("_token_balances.html", address_hash: address_hash, token_balances: []) end else _ -> diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex index e12d14cb77..fd79d25b0b 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex @@ -32,7 +32,11 @@ defmodule BlockScoutWeb.Tokens.HolderController do token_balances_json = Enum.map(token_balances_paginated, fn token_balance -> - View.render_to_string(HolderView, "_token_balances.html", token_balance: token_balance, token: token) + View.render_to_string(HolderView, "_token_balances.html", + address_hash: address_hash, + token_balance: token_balance, + token: token + ) end) json(conn, %{items: token_balances_json, next_page_path: next_page_path}) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex index 100d4f0262..2e5a4d520d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex @@ -11,6 +11,9 @@ <%= tokens_count_title(@token_balances) %> + <%= if @token_balances && Decimal.cmp(address_tokens_usd_sum_cache(@address_hash, @token_balances), Decimal.new(0)) == :gt do %> + ( >) + <% end %> <% else %> <%= tokens_count_title(@token_balances) %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex index e25a51a30a..becc9802ff 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_tokens.html.eex @@ -18,7 +18,7 @@

<%= token_name(token_balance.token) %>

<%= if token_balance.token.usd_value do %>

- +

<% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_token_balance_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_token_balance_view.ex index bf18454ab4..00853c09a5 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_token_balance_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_token_balance_view.ex @@ -1,7 +1,8 @@ defmodule BlockScoutWeb.AddressTokenBalanceView do use BlockScoutWeb, :view - alias BlockScoutWeb.CurrencyHelpers + alias Explorer.Chain + alias Explorer.Counters.AddressTokenUsdSum def tokens_count_title(token_balances) do ngettext("%{count} token", "%{count} tokens", Enum.count(token_balances)) @@ -57,7 +58,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceView do defp sort_2_tokens_by_value_desc_and_name(token_balance1, token_balance2, usd_value1, usd_value2, sort_by_name) when not is_nil(usd_value1) and not is_nil(usd_value2) do - case Decimal.cmp(balance_in_usd(token_balance1), balance_in_usd(token_balance2)) do + case Decimal.cmp(Chain.balance_in_usd(token_balance1), Chain.balance_in_usd(token_balance2)) do :gt -> true @@ -84,16 +85,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceView do sort_by_name end - @doc """ - Return the balance in usd corresponding to this token. Return nil if the usd_value of the token is not present. - """ - def balance_in_usd(%{token: %{usd_value: nil}}) do - nil - end - - def balance_in_usd(token_balance) do - tokens = CurrencyHelpers.divide_decimals(token_balance.value, token_balance.token.decimals) - price = token_balance.token.usd_value - Decimal.mult(tokens, price) + def address_tokens_usd_sum_cache(address, token_balances) do + AddressTokenUsdSum.fetch(address, token_balances) end end diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 017e886c0c..4c4a202d5d 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -1,5 +1,5 @@ #, elixir-format -#: lib/block_scout_web/views/address_token_balance_view.ex:7 +#: lib/block_scout_web/views/address_token_balance_view.ex:8 msgid "%{count} token" msgid_plural "%{count} tokens" msgstr[0] "" @@ -1262,7 +1262,7 @@ msgstr "" #, elixir-format #: -#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:30 +#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:33 msgid "Search tokens" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 017e886c0c..4c4a202d5d 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -1,5 +1,5 @@ #, elixir-format -#: lib/block_scout_web/views/address_token_balance_view.ex:7 +#: lib/block_scout_web/views/address_token_balance_view.ex:8 msgid "%{count} token" msgid_plural "%{count} tokens" msgstr[0] "" @@ -1262,7 +1262,7 @@ msgstr "" #, elixir-format #: -#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:30 +#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:33 msgid "Search tokens" msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/views/address_token_balance_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/address_token_balance_view_test.exs index 29e508ba96..c61a776edc 100644 --- a/apps/block_scout_web/test/block_scout_web/views/address_token_balance_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/address_token_balance_view_test.exs @@ -2,6 +2,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do use BlockScoutWeb.ConnCase, async: true alias BlockScoutWeb.AddressTokenBalanceView + alias Explorer.Chain describe "tokens_count_title/1" do test "returns the title pluralized" do @@ -146,7 +147,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do token_balance = build(:token_balance, value: Decimal.new(10), token: token) - result = AddressTokenBalanceView.balance_in_usd(token_balance) + result = Chain.balance_in_usd(token_balance) assert Decimal.cmp(result, 30) == :eq end @@ -159,7 +160,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do token_balance = build(:token_balance, value: 10, token: token) - assert AddressTokenBalanceView.balance_in_usd(token_balance) == nil + assert Chain.balance_in_usd(token_balance) == nil end test "consider decimals when computing value" do @@ -170,7 +171,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceViewTest do token_balance = build(:token_balance, value: Decimal.new(10), token: token) - result = AddressTokenBalanceView.balance_in_usd(token_balance) + result = Chain.balance_in_usd(token_balance) assert Decimal.cmp(result, Decimal.from_float(0.3)) == :eq end diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 3a5c38803a..7463bed2d2 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -105,6 +105,17 @@ config :explorer, Explorer.Counters.AddressTransactionsGasUsageCounter, enable_consolidation: true, period: address_transactions_gas_usage_counter_cache_period +address_tokens_usd_sum_cache_period = + case Integer.parse(System.get_env("ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD", "")) do + {secs, ""} -> :timer.seconds(secs) + _ -> :timer.hours(1) + end + +config :explorer, Explorer.Counters.AddressTokenUsdSum, + enabled: true, + enable_consolidation: true, + period: address_tokens_usd_sum_cache_period + token_holders_counter_cache_period = case Integer.parse(System.get_env("TOKEN_HOLDERS_COUNTER_CACHE_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 8675a13458..ce8b667b87 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -82,6 +82,7 @@ defmodule Explorer.Application do configure(Explorer.Counters.AddressesCounter), configure(Explorer.Counters.AddressTransactionsCounter), configure(Explorer.Counters.AddressTransactionsGasUsageCounter), + configure(Explorer.Counters.AddressTokenUsdSum), configure(Explorer.Counters.TokenHoldersCounter), configure(Explorer.Counters.TokenTransfersCounter), configure(Explorer.Counters.AverageBlockTime), diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 8c35720790..bd2e8bca55 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -44,6 +44,7 @@ defmodule Explorer.Chain do Address.TokenBalance, Block, BridgedToken, + CurrencyHelpers, Data, DecompiledSmartContract, Hash, @@ -2012,6 +2013,30 @@ defmodule Explorer.Chain do end end + @doc """ + Return the balance in usd corresponding to this token. Return nil if the usd_value of the token is not present. + """ + def balance_in_usd(%{token: %{usd_value: nil}}) do + nil + end + + def balance_in_usd(token_balance) do + tokens = CurrencyHelpers.divide_decimals(token_balance.value, token_balance.token.decimals) + price = token_balance.token.usd_value + Decimal.mult(tokens, price) + end + + def address_tokens_usd_sum(token_balances) do + token_balances + |> Enum.reduce(Decimal.new(0), fn token_balance, acc -> + if token_balance.value && token_balance.token.usd_value do + Decimal.add(acc, balance_in_usd(token_balance)) + else + acc + end + end) + end + defp contract?(%{contract_code: nil}), do: false defp contract?(%{contract_code: _}), do: true diff --git a/apps/explorer/lib/explorer/chain/currency_helpers.ex b/apps/explorer/lib/explorer/chain/currency_helpers.ex new file mode 100644 index 0000000000..2adcbac8f7 --- /dev/null +++ b/apps/explorer/lib/explorer/chain/currency_helpers.ex @@ -0,0 +1,12 @@ +defmodule Explorer.Chain.CurrencyHelpers do + @moduledoc """ + Helper functions for interacting with `t:BlockScoutWeb.ExchangeRates.USD.t/0` values. + """ + + @spec divide_decimals(Decimal.t(), Decimal.t()) :: Decimal.t() + def divide_decimals(%{sign: sign, coef: coef, exp: exp}, decimals) do + sign + |> Decimal.new(coef, exp - Decimal.to_integer(decimals)) + |> Decimal.normalize() + end +end diff --git a/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex new file mode 100644 index 0000000000..e665733fa9 --- /dev/null +++ b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex @@ -0,0 +1,112 @@ +defmodule Explorer.Counters.AddressTokenUsdSum do + @moduledoc """ + Caches Address tokens USD value. + """ + use GenServer + + alias Explorer.Chain + + @cache_name :address_tokens_usd_value + @last_update_key "last_update" + @cache_period Application.get_env(:explorer, __MODULE__)[:period] + + @ets_opts [ + :set, + :named_table, + :public, + read_concurrency: true + ] + + config = Application.get_env(:explorer, Explorer.Counters.AddressTokenUsdSum) + @enable_consolidation Keyword.get(config, :enable_consolidation) + + @spec start_link(term()) :: GenServer.on_start() + def start_link(_) do + GenServer.start_link(__MODULE__, :ok, name: __MODULE__) + end + + @impl true + def init(_args) do + create_cache_table() + + {:ok, %{consolidate?: enable_consolidation?()}, {:continue, :ok}} + end + + @impl true + def handle_continue(:ok, %{consolidate?: true} = state) do + {:noreply, state} + end + + @impl true + def handle_continue(:ok, state) do + {:noreply, state} + end + + @impl true + def handle_info(:consolidate, state) do + {:noreply, state} + end + + def fetch(address_hash, token_balances) do + if cache_expired?(address_hash) do + Task.start_link(fn -> + update_cache(address_hash, token_balances) + end) + end + + address_hash_string = get_address_hash_string(address_hash) + fetch_from_cache("hash_#{address_hash_string}") + end + + def cache_name, do: @cache_name + + defp cache_expired?(address_hash) do + address_hash_string = get_address_hash_string(address_hash) + updated_at = fetch_from_cache("hash_#{address_hash_string}_#{@last_update_key}") + + cond do + is_nil(updated_at) -> true + current_time() - updated_at > @cache_period -> true + true -> false + end + end + + defp update_cache(address_hash, token_balances) do + address_hash_string = get_address_hash_string(address_hash) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + new_data = Chain.address_tokens_usd_sum(token_balances) + put_into_cache("hash_#{address_hash_string}", new_data) + end + + defp fetch_from_cache(key) do + case :ets.lookup(@cache_name, key) do + [{_, value}] -> + value + + [] -> + 0 + end + end + + defp put_into_cache(key, value) do + :ets.insert(@cache_name, {key, value}) + end + + defp get_address_hash_string(address_hash) do + Base.encode16(address_hash.bytes, case: :lower) + end + + defp current_time do + utc_now = DateTime.utc_now() + + DateTime.to_unix(utc_now, :millisecond) + end + + def create_cache_table do + if :ets.whereis(@cache_name) == :undefined do + :ets.new(@cache_name, @ets_opts) + end + end + + def enable_consolidation?, do: @enable_consolidation +end From ef7d5c9f1b3649cc4e139a4070faff1c82d0dfe3 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Mon, 23 Nov 2020 11:01:31 +0300 Subject: [PATCH 2/3] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ab35aaab..e72969c8c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#3470](https://github.com/poanetwork/blockscout/pull/3470) - Display sum of tokens' USD value at tokens holder's address page - [#3462](https://github.com/poanetwork/blockscout/pull/3462) - Display price for bridged tokens ### Fixes From ced4ddd25b082397c600493291e23a3d8386ccba Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Mon, 23 Nov 2020 17:29:40 +0300 Subject: [PATCH 3/3] Refactor cache for tokens exchange rates --- apps/explorer/config/config.exs | 11 ++ apps/explorer/lib/explorer/application.ex | 1 + .../chain/cache/token_exchange_rate.ex | 132 ++++++++++++++++++ .../lib/explorer/chain/supply/token_bridge.ex | 16 +-- apps/explorer/lib/explorer/counters/bridge.ex | 41 +----- 5 files changed, 159 insertions(+), 42 deletions(-) create mode 100644 apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 7463bed2d2..a6290bdfb2 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -116,6 +116,17 @@ config :explorer, Explorer.Counters.AddressTokenUsdSum, enable_consolidation: true, period: address_tokens_usd_sum_cache_period +token_exchange_rate_cache_period = + case Integer.parse(System.get_env("TOKEN_EXCHANGE_RATE_CACHE_PERIOD", "")) do + {secs, ""} -> :timer.seconds(secs) + _ -> :timer.hours(1) + end + +config :explorer, Explorer.Chain.Cache.TokenExchangeRate, + enabled: true, + enable_consolidation: true, + period: token_exchange_rate_cache_period + token_holders_counter_cache_period = case Integer.parse(System.get_env("TOKEN_HOLDERS_COUNTER_CACHE_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index ce8b667b87..f84cdd30b9 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -76,6 +76,7 @@ defmodule Explorer.Application do configure(Explorer.ChainSpec.GenesisData), configure(Explorer.KnownTokens), configure(Explorer.Market.History.Cataloger), + configure(Explorer.Chain.Cache.TokenExchangeRate), configure(Explorer.Chain.Transaction.History.Historian), configure(Explorer.Chain.Events.Listener), configure(Explorer.Counters.AddressesWithBalanceCounter), diff --git a/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex b/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex new file mode 100644 index 0000000000..6a2b4a93fb --- /dev/null +++ b/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex @@ -0,0 +1,132 @@ +defmodule Explorer.Chain.Cache.TokenExchangeRate do + @moduledoc """ + Caches Token USD exchange_rate. + """ + use GenServer + + alias Explorer.ExchangeRates.Source + + @cache_name :token_exchange_rate + @last_update_key "last_update" + @cache_period Application.get_env(:explorer, __MODULE__)[:period] + + @ets_opts [ + :set, + :named_table, + :public, + read_concurrency: true + ] + + config = Application.get_env(:explorer, Explorer.Chain.Cache.TokenExchangeRate) + @enable_consolidation Keyword.get(config, :enable_consolidation) + + @spec start_link(term()) :: GenServer.on_start() + def start_link(_) do + GenServer.start_link(__MODULE__, :ok, name: __MODULE__) + end + + @impl true + def init(_args) do + create_cache_table() + + {:ok, %{consolidate?: enable_consolidation?()}, {:continue, :ok}} + end + + @impl true + def handle_continue(:ok, %{consolidate?: true} = state) do + {:noreply, state} + end + + @impl true + def handle_continue(:ok, state) do + {:noreply, state} + end + + @impl true + def handle_info(:consolidate, state) do + {:noreply, state} + end + + def cache_key(symbol) do + "token_symbol_exchange_rate_#{symbol}" + end + + def fetch(symbol) do + if cache_expired?(symbol) || value_is_empty?(symbol) do + Task.start_link(fn -> + update_cache(symbol) + end) + end + + fetch_from_cache(cache_key(symbol)) + end + + def cache_name, do: @cache_name + + defp cache_expired?(symbol) do + updated_at = fetch_from_cache("#{cache_key(symbol)}_#{@last_update_key}") + + cond do + is_nil(updated_at) -> true + current_time() - updated_at > @cache_period -> true + true -> false + end + end + + defp value_is_empty?(symbol) do + value = fetch_from_cache(cache_key(symbol)) + is_nil(value) || value == 0 + end + + defp update_cache(symbol) do + put_into_cache("#{cache_key(symbol)}_#{@last_update_key}", current_time()) + + exchange_rate = fetch_token_exchange_rate(symbol) + + put_into_cache(cache_key(symbol), exchange_rate) + end + + def fetch_token_exchange_rate(symbol) do + case Source.fetch_exchange_rates_for_token(symbol) do + {:ok, [rates]} -> + rates.usd_value + + _ -> + nil + end + end + + defp fetch_from_cache(key) do + case :ets.lookup(@cache_name, key) do + [{_, value}] -> + value + + [] -> + 0 + end + end + + def put_into_cache(key, value) do + if cache_table_exists?() do + :ets.insert(@cache_name, {key, value}) + end + end + + defp current_time do + utc_now = DateTime.utc_now() + + DateTime.to_unix(utc_now, :millisecond) + end + + def cache_table_exists? do + :ets.whereis(@cache_name) !== :undefined + end + + def create_cache_table do + unless cache_table_exists?() do + :ets.new(@cache_name, @ets_opts) + end + end + + def enable_consolidation?, do: @enable_consolidation +end diff --git a/apps/explorer/lib/explorer/chain/supply/token_bridge.ex b/apps/explorer/lib/explorer/chain/supply/token_bridge.ex index 72d31b89b7..1b03e60228 100644 --- a/apps/explorer/lib/explorer/chain/supply/token_bridge.ex +++ b/apps/explorer/lib/explorer/chain/supply/token_bridge.ex @@ -11,6 +11,7 @@ defmodule Explorer.Chain.Supply.TokenBridge do ] alias Explorer.Chain.{BridgedToken, Token, Wei} + alias Explorer.Chain.Cache.TokenExchangeRate, as: TokenExchangeRateCache alias Explorer.Counters.Bridge alias Explorer.ExchangeRates.Source alias Explorer.Repo @@ -198,13 +199,7 @@ defmodule Explorer.Chain.Supply.TokenBridge do def get_current_price_for_bridged_token(symbol) do bridged_token_symbol_for_price_fetching = bridged_token_symbol_mapping_to_get_price(symbol) - case Source.fetch_exchange_rates_for_token(bridged_token_symbol_for_price_fetching) do - {:ok, [rates]} -> - rates.usd_value - - _ -> - nil - end + TokenExchangeRateCache.fetch(bridged_token_symbol_for_price_fetching) end def get_bridged_mainnet_tokens_list do @@ -224,7 +219,12 @@ defmodule Explorer.Chain.Supply.TokenBridge do bridged_mainnet_tokens_with_supply = bridged_mainnet_tokens_list |> Enum.map(fn {bridged_token_hash, bridged_token_symbol} -> - bridged_token_price = Bridge.fetch_token_price(bridged_token_symbol) + bridged_token_price = + if TokenExchangeRateCache.fetch(bridged_token_symbol) > 0 do + TokenExchangeRateCache.fetch(bridged_token_symbol) + else + TokenExchangeRateCache.fetch_token_exchange_rate(bridged_token_symbol) + end query = from(t in Token, diff --git a/apps/explorer/lib/explorer/counters/bridge.ex b/apps/explorer/lib/explorer/counters/bridge.ex index e59806a070..0309369eec 100644 --- a/apps/explorer/lib/explorer/counters/bridge.ex +++ b/apps/explorer/lib/explorer/counters/bridge.ex @@ -1,15 +1,15 @@ defmodule Explorer.Counters.Bridge do @moduledoc """ - Caches the prices of bridged tokens. + Caches the total supply of TokenBridge and OmniBridge. It loads the count asynchronously and in a time interval of 30 minutes. """ use GenServer + alias Explorer.Chain.Cache.TokenExchangeRate alias Explorer.Chain.Supply.TokenBridge - @prices_table :omni_bridge_bridged_tokens_prices @bridges_table :bridges_market_cap @current_total_supply_from_token_bridge_cache_key "current_total_supply_from_token_bridge" @@ -22,10 +22,6 @@ defmodule Explorer.Counters.Bridge do read_concurrency: true ] - def price_cache_key(symbol) do - "token_symbol_price_#{symbol}" - end - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of @@ -51,16 +47,6 @@ defmodule Explorer.Counters.Bridge do {:ok, %{consolidate?: enable_consolidation?()}, {:continue, :ok}} end - def prices_table_exists? do - :ets.whereis(@prices_table) !== :undefined - end - - def create_prices_table do - unless prices_table_exists?() do - :ets.new(@prices_table, @ets_opts) - end - end - def bridges_table_exists? do :ets.whereis(@bridges_table) !== :undefined end @@ -72,7 +58,7 @@ defmodule Explorer.Counters.Bridge do end def create_tables do - create_prices_table() + TokenExchangeRate.create_cache_table() create_bridges_table() end @@ -84,8 +70,8 @@ defmodule Explorer.Counters.Bridge do Inserts new bridged token price into the `:ets` table. """ def insert_price({key, info}) do - if prices_table_exists?() do - :ets.insert(@prices_table, {key, info}) + if TokenExchangeRate.cache_table_exists?() do + TokenExchangeRate.put_into_cache(key, info) end end @@ -110,20 +96,6 @@ defmodule Explorer.Counters.Bridge do {:noreply, state} end - @doc """ - Fetches the info for a specific item from the `:ets` table. - """ - def fetch_token_price(symbol) do - if prices_table_exists?() do - do_fetch_token_price(:ets.lookup(@prices_table, price_cache_key(symbol))) - else - 0 - end - end - - defp do_fetch_token_price([{_, result}]), do: result - defp do_fetch_token_price([]), do: 0 - def fetch_token_bridge_total_supply do if bridges_table_exists?() do do_fetch_token_bridge_total_supply(:ets.lookup(@bridges_table, @current_total_supply_from_token_bridge_cache_key)) @@ -191,7 +163,8 @@ defmodule Explorer.Counters.Bridge do bridged_mainnet_tokens_list |> Enum.each(fn {_bridged_token_hash, bridged_token_symbol} -> bridged_token_price = TokenBridge.get_current_price_for_bridged_token(bridged_token_symbol) - insert_price({price_cache_key(bridged_token_symbol), bridged_token_price}) + cache_key = TokenExchangeRate.cache_key(bridged_token_symbol) + TokenExchangeRate.put_into_cache(cache_key, bridged_token_price) end) update_total_supply_from_token_bridge_cache()