diff --git a/apps/indexer/lib/indexer/fetcher/token_instance.ex b/apps/indexer/lib/indexer/fetcher/token_instance.ex index 81b7703f2a..f489652400 100644 --- a/apps/indexer/lib/indexer/fetcher/token_instance.ex +++ b/apps/indexer/lib/indexer/fetcher/token_instance.ex @@ -9,7 +9,7 @@ defmodule Indexer.Fetcher.TokenInstance do require Logger alias Explorer.{Chain, Repo} - alias Explorer.Chain.{Cache.BlockNumber, Token} + alias Explorer.Chain.{Address, Cache.BlockNumber, Token} alias Explorer.Token.{InstanceMetadataRetriever, InstanceOwnerReader} alias Indexer.BufferedTask @@ -100,17 +100,12 @@ defmodule Indexer.Fetcher.TokenInstance do end defp update_current_token_balances(token_contract_address_hash, token_ids) do - import_params = - token_ids - |> Enum.map(&instance_owner_request(token_contract_address_hash, &1)) - |> InstanceOwnerReader.get_owner_of() - |> Enum.map(¤t_token_balances_import_params/1) - - Chain.import(%{ - address_current_token_balances: %{ - params: import_params - } - }) + token_ids + |> Enum.map(&instance_owner_request(token_contract_address_hash, &1)) + |> InstanceOwnerReader.get_owner_of() + |> Enum.map(¤t_token_balances_import_params/1) + |> all_import_params() + |> Chain.import() end defp instance_owner_request(token_contract_address_hash, token_id) do @@ -132,6 +127,29 @@ defmodule Indexer.Fetcher.TokenInstance do } end + defp all_import_params(balances_import_params) do + addresses_import_params = + balances_import_params + |> Enum.reduce([], fn %{address_hash: address_hash}, acc -> + case Repo.get_by(Address, hash: address_hash) do + nil -> [%{hash: address_hash} | acc] + _address -> acc + end + end) + |> case do + [] -> %{} + params -> %{addresses: %{params: params}} + end + + current_token_balances_import_params = %{ + address_current_token_balances: %{ + params: balances_import_params + } + } + + Map.merge(current_token_balances_import_params, addresses_import_params) + end + @doc """ Fetches token instance data asynchronously. """ diff --git a/apps/indexer/test/indexer/fetcher/token_instance_test.exs b/apps/indexer/test/indexer/fetcher/token_instance_test.exs index 44619489c1..d25ac501f1 100644 --- a/apps/indexer/test/indexer/fetcher/token_instance_test.exs +++ b/apps/indexer/test/indexer/fetcher/token_instance_test.exs @@ -4,6 +4,8 @@ defmodule Indexer.Fetcher.TokenInstanceTest do import Mox + alias Explorer.Chain + alias Explorer.Chain.Address alias Explorer.Chain.Address.CurrentTokenBalance alias Explorer.Repo alias Indexer.Fetcher.TokenInstance @@ -44,5 +46,42 @@ defmodule Indexer.Fetcher.TokenInstanceTest do address_hash: ^address_hash } = Repo.one(CurrentTokenBalance) end + + test "updates current token balance with missing address" do + token = insert(:token, type: "ERC-1155") + token_contract_address_hash = token.contract_address_hash + instance = insert(:token_instance, token_contract_address_hash: token_contract_address_hash) + token_id = instance.token_id + {:ok, address_hash} = Chain.string_to_address_hash("0x57e93bb58268de818b42e3795c97bad58afcd3fe") + + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0xc87b56dd" <> _}, _]}], _ -> + {:ok, + [ + %{ + id: 0, + result: + "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000027b7d000000000000000000000000000000000000000000000000000000000000" + } + ]} + end) + |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0x6352211e" <> _}, _]}], _ -> + {:ok, [%{id: 0, result: "0x00000000000000000000000057e93bb58268de818b42e3795c97bad58afcd3fe"}]} + end) + + TokenInstance.run( + [%{contract_address_hash: token_contract_address_hash, token_id: token_id, token_ids: nil}], + nil + ) + + assert %{ + token_id: ^token_id, + token_type: "ERC-1155", + token_contract_address_hash: ^token_contract_address_hash, + address_hash: ^address_hash + } = Repo.one(CurrentTokenBalance) + + assert %Address{} = Repo.get_by(Address, hash: address_hash) + end end end