diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 4c7914a7ff..4dc297fef1 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -938,7 +938,7 @@ defmodule Explorer.Chain do def stream_unfetched_token_balances(initial, reducer) when is_function(reducer, 2) do Repo.transaction( fn -> - query = from(tb in TokenBalance, where: is_nil(tb.value_fetched_at)) + query = TokenBalance.unfetched_token_balances() query |> Repo.stream(timeout: :infinity) diff --git a/apps/explorer/lib/explorer/chain/address/token_balance.ex b/apps/explorer/lib/explorer/chain/address/token_balance.ex index c8dec08d45..c7a9eefed5 100644 --- a/apps/explorer/lib/explorer/chain/address/token_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/token_balance.ex @@ -129,4 +129,24 @@ defmodule Explorer.Chain.Address.TokenBalance do tb.value < ^value or (tb.value == ^value and tb.address_hash < ^address_hash) ) end + + {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") + @burn_address_hash burn_address_hash + + @doc """ + Builds an `Ecto.Query` to fetch the unfetched token balances. + + Unfetched token balances are the ones that have the column `value_fetched_at` nil. This query also + ignores the burn_address for tokens ERC-721 since the most tokens ERC-721 don't allow get the + balance for burn_address. + """ + def unfetched_token_balances do + from( + tb in TokenBalance, + join: t in Token, + on: tb.token_contract_address_hash == t.contract_address_hash, + where: is_nil(tb.value_fetched_at), + where: (tb.address_hash != ^@burn_address_hash and t.type != "ERC-721") or t.type == "ERC-20" + ) + end end diff --git a/apps/explorer/test/explorer/chain/address/token_balance_test.ex b/apps/explorer/test/explorer/chain/address/token_balance_test.ex new file mode 100644 index 0000000000..4c59c675bf --- /dev/null +++ b/apps/explorer/test/explorer/chain/address/token_balance_test.ex @@ -0,0 +1,79 @@ +defmodule Explorer.Chain.Address.TokenBalanceTest do + use Explorer.DataCase + + alias Explorer.Repo + alias Explorer.Chain.Address.TokenBalance + + describe "unfetched_token_balances/0" do + test "returns only the token balances that have value_fetched_at nil" do + address = insert(:address, hash: "0xc45e4830dff873cf8b70de2b194d0ddd06ef651e") + token_balance = insert(:token_balance, value_fetched_at: nil, address: address) + insert(:token_balance) + + result = + TokenBalance.unfetched_token_balances() + |> Repo.all() + |> List.first() + + assert result.block_number == token_balance.block_number + end + + test "does not ignore token balance when the address isn't the burn address with Token ERC-20" do + address = insert(:address, hash: "0xc45e4830dff873cf8b70de2b194d0ddd06ef651e") + token = insert(:token, type: "ERC-20") + + token_balance = + insert( + :token_balance, + value_fetched_at: nil, + address: address, + token_contract_address_hash: token.contract_address_hash + ) + + result = + TokenBalance.unfetched_token_balances() + |> Repo.all() + |> List.first() + + assert result.block_number == token_balance.block_number + end + + test "ignores the burn_address when the token type is ERC-721" do + burn_address = insert(:address, hash: "0x0000000000000000000000000000000000000000") + token = insert(:token, type: "ERC-721") + + insert( + :token_balance, + address: burn_address, + token_contract_address_hash: token.contract_address_hash, + value_fetched_at: nil + ) + + result = + TokenBalance.unfetched_token_balances() + |> Repo.all() + + assert result == [] + end + + test "does not ignore the burn_address when the token type is ERC-20" do + burn_address = insert(:address, hash: "0x0000000000000000000000000000000000000000") + token = insert(:token, type: "ERC-20") + + token_balance = + insert( + :token_balance, + address: burn_address, + token_contract_address_hash: token.contract_address_hash, + value_fetched_at: nil + ) + + result = + TokenBalance.unfetched_token_balances() + |> Repo.all() + |> List.first() + + assert result.block_number == token_balance.block_number + end + end +end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 69d99c71fa..285f2a8523 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -2326,8 +2326,9 @@ defmodule Explorer.ChainTest do end describe "stream_unfetched_token_balances/2" do - test "returns only the token balances that have value_fetched_at nil" do - token_balance = insert(:token_balance, value_fetched_at: nil) + test "executes the given reducer with the query result" do + address = insert(:address, hash: "0xc45e4830dff873cf8b70de2b194d0ddd06ef651e") + token_balance = insert(:token_balance, value_fetched_at: nil, address: address) insert(:token_balance) assert Chain.stream_unfetched_token_balances([], &[&1.block_number | &2]) == {:ok, [token_balance.block_number]}