From 80a8e3b4641cccf2d4b9d9d23c78b4430c8203a9 Mon Sep 17 00:00:00 2001 From: nikitosing <32202610+nikitosing@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:56:20 +0300 Subject: [PATCH] fix: Filter WETH transfers in indexer + migration to delete historical incorrect WETH transfers (#10134) --- apps/explorer/config/config.exs | 1 + apps/explorer/config/runtime/test.exs | 1 + apps/explorer/lib/explorer/application.ex | 1 + .../lib/explorer/chain/token_transfer.ex | 12 ++ ...sanitize_incorrect_weth_token_transfers.ex | 145 ++++++++++++++++ ...ze_incorrect_weth_token_transfers_test.exs | 161 ++++++++++++++++++ .../lib/indexer/transform/token_transfers.ex | 33 +++- .../transform/token_transfers_test.exs | 153 +++++++++++++++++ config/runtime.exs | 7 + 9 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 apps/explorer/lib/explorer/migrator/sanitize_incorrect_weth_token_transfers.ex create mode 100644 apps/explorer/test/explorer/migrator/sanitize_incorrect_weth_token_transfers_test.exs diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 78aded683b..88e78975d1 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -122,6 +122,7 @@ config :explorer, Explorer.Migrator.AddressTokenBalanceTokenType, enabled: true config :explorer, Explorer.Migrator.SanitizeMissingBlockRanges, enabled: true config :explorer, Explorer.Migrator.SanitizeIncorrectNFTTokenTransfers, enabled: true config :explorer, Explorer.Migrator.TokenTransferTokenType, enabled: true +config :explorer, Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers, enabled: true config :explorer, Explorer.Chain.Fetcher.CheckBytecodeMatchingOnDemand, enabled: true diff --git a/apps/explorer/config/runtime/test.exs b/apps/explorer/config/runtime/test.exs index d9cfc1a821..368874b219 100644 --- a/apps/explorer/config/runtime/test.exs +++ b/apps/explorer/config/runtime/test.exs @@ -44,6 +44,7 @@ config :explorer, Explorer.Migrator.AddressTokenBalanceTokenType, enabled: false config :explorer, Explorer.Migrator.SanitizeMissingBlockRanges, enabled: false config :explorer, Explorer.Migrator.SanitizeIncorrectNFTTokenTransfers, enabled: false config :explorer, Explorer.Migrator.TokenTransferTokenType, enabled: false +config :explorer, Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers, enabled: false config :explorer, realtime_events_sender: Explorer.Chain.Events.SimpleSender diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 9fa12bb729..e2ffa55fed 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -137,6 +137,7 @@ defmodule Explorer.Application do configure(Explorer.Migrator.SanitizeMissingBlockRanges), configure(Explorer.Migrator.SanitizeIncorrectNFTTokenTransfers), configure(Explorer.Migrator.TokenTransferTokenType), + configure(Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers), configure_chain_type_dependent_process(Explorer.Chain.Cache.StabilityValidatorsCounters, :stability) ] |> List.flatten() diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex index d0a33a1d30..69f309410d 100644 --- a/apps/explorer/lib/explorer/chain/token_transfer.ex +++ b/apps/explorer/lib/explorer/chain/token_transfer.ex @@ -528,4 +528,16 @@ defmodule Explorer.Chain.TokenTransfer do defp logs_to_token_transfers_query(query, []) do query end + + @doc """ + Checks if `WHITELISTED_WETH_CONTRACTS` env contains provided address hash. + WHITELISTED_WETH_CONTRACTS env is the list of whitelisted WETH contracts addresses. + """ + @spec whitelisted_weth_contract?(any()) :: boolean() + def whitelisted_weth_contract?(contract_address_hash), + do: + (contract_address_hash |> to_string() |> String.downcase()) in Application.get_env( + :explorer, + Explorer.Chain.TokenTransfer + )[:whitelisted_weth_contracts] end diff --git a/apps/explorer/lib/explorer/migrator/sanitize_incorrect_weth_token_transfers.ex b/apps/explorer/lib/explorer/migrator/sanitize_incorrect_weth_token_transfers.ex new file mode 100644 index 0000000000..5759f91336 --- /dev/null +++ b/apps/explorer/lib/explorer/migrator/sanitize_incorrect_weth_token_transfers.ex @@ -0,0 +1,145 @@ +defmodule Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers do + @moduledoc """ + This migrator will delete all incorrect WETH token transfers. As incorrect we consider: + - WETH withdrawals and WETH deposits emitted by tokens which are not in `WHITELISTED_WETH_CONTRACTS` env + - WETH withdrawal or WETH deposit which has sibling token transfer within the same block and transaction, with the same amount, same from and to addresses, same token contract addresses. (We consider such pairs as duplicates) + """ + + use GenServer, restart: :transient + + import Ecto.Query + + require Logger + + alias Explorer.Chain.{Log, TokenTransfer} + alias Explorer.Migrator.MigrationStatus + alias Explorer.Repo + + @migration_name "sanitize_incorrect_weth_transfers" + @default_batch_size 500 + + def start_link(_) do + GenServer.start_link(__MODULE__, :ok, name: __MODULE__) + end + + @impl true + def init(_) do + case MigrationStatus.get_status(@migration_name) do + "completed" -> + :ignore + + _ -> + MigrationStatus.set_status(@migration_name, "started") + schedule_batch_migration() + {:ok, %{step: :delete_not_whitelisted_weth_transfers}} + end + end + + @impl true + def handle_info(:migrate_batch, %{step: step} = state) do + case last_unprocessed_identifiers(step) do + [] -> + case step do + :delete_not_whitelisted_weth_transfers -> + Logger.info( + "SanitizeIncorrectWETHTokenTransfers deletion of not whitelisted weth transfers finished, continuing with duplicates deletion" + ) + + schedule_batch_migration() + {:noreply, %{step: :delete_duplicates}} + + :delete_duplicates -> + Logger.info("SanitizeIncorrectWETHTokenTransfers migration finished") + MigrationStatus.set_status(@migration_name, "completed") + {:stop, :normal, state} + end + + identifiers -> + identifiers + |> Enum.chunk_every(batch_size()) + |> Enum.map(&run_task/1) + |> Task.await_many(:infinity) + + schedule_batch_migration() + + {:noreply, state} + end + end + + defp last_unprocessed_identifiers(step) do + limit = batch_size() * concurrency() + + step + |> unprocessed_identifiers() + |> limit(^limit) + |> Repo.all(timeout: :infinity) + end + + defp unprocessed_identifiers(:delete_duplicates) do + weth_transfers = + from( + tt in TokenTransfer, + left_join: l in Log, + on: tt.block_hash == l.block_hash and tt.transaction_hash == l.transaction_hash and tt.log_index == l.index, + where: + l.first_topic == ^TokenTransfer.weth_deposit_signature() or + l.first_topic == ^TokenTransfer.weth_withdrawal_signature() + ) + + from( + weth_tt in subquery(weth_transfers), + inner_join: tt in TokenTransfer, + on: weth_tt.block_hash == tt.block_hash and weth_tt.transaction_hash == tt.transaction_hash, + where: + weth_tt.log_index != tt.log_index and weth_tt.token_contract_address_hash == tt.token_contract_address_hash and + weth_tt.to_address_hash == tt.to_address_hash and weth_tt.from_address_hash == tt.from_address_hash and + weth_tt.amount == tt.amount, + select: {weth_tt.transaction_hash, weth_tt.block_hash, weth_tt.log_index} + ) + end + + defp unprocessed_identifiers(:delete_not_whitelisted_weth_transfers) do + from( + tt in TokenTransfer, + left_join: l in Log, + on: tt.block_hash == l.block_hash and tt.transaction_hash == l.transaction_hash and tt.log_index == l.index, + where: + (l.first_topic == ^TokenTransfer.weth_deposit_signature() or + l.first_topic == ^TokenTransfer.weth_withdrawal_signature()) and + tt.token_contract_address_hash not in ^Application.get_env(:explorer, Explorer.Chain.TokenTransfer)[ + :whitelisted_weth_contracts + ], + select: {tt.transaction_hash, tt.block_hash, tt.log_index} + ) + end + + defp run_task(batch), do: Task.async(fn -> handle_batch(batch) end) + + defp handle_batch(token_transfer_ids) do + token_transfer_ids + |> build_delete_query() + |> Repo.query!([], timeout: :infinity) + end + + defp schedule_batch_migration do + Process.send(self(), :migrate_batch, []) + end + + defp batch_size do + Application.get_env(:explorer, __MODULE__)[:batch_size] || @default_batch_size + end + + defp concurrency do + default = 4 * System.schedulers_online() + + Application.get_env(:explorer, __MODULE__)[:concurrency] || default + end + + defp build_delete_query(token_transfer_ids) do + """ + DELETE + FROM token_transfers tt + WHERE (tt.transaction_hash, tt.block_hash, tt.log_index) IN #{TokenTransfer.encode_token_transfer_ids(token_transfer_ids)} + """ + end +end diff --git a/apps/explorer/test/explorer/migrator/sanitize_incorrect_weth_token_transfers_test.exs b/apps/explorer/test/explorer/migrator/sanitize_incorrect_weth_token_transfers_test.exs new file mode 100644 index 0000000000..834c3d8054 --- /dev/null +++ b/apps/explorer/test/explorer/migrator/sanitize_incorrect_weth_token_transfers_test.exs @@ -0,0 +1,161 @@ +defmodule Explorer.Migrator.SanitizeIncorrectWETHTokenTransfersTest do + use Explorer.DataCase, async: false + + alias Explorer.Chain.TokenTransfer + alias Explorer.Migrator.{SanitizeIncorrectWETHTokenTransfers, MigrationStatus} + alias Explorer.Repo + + describe "SanitizeIncorrectWETHTokenTransfers" do + test "Deletes not whitelisted WETH transfers and duplicated WETH transfers" do + %{contract_address: token_address} = insert(:token, type: "ERC-20") + block = insert(:block, consensus: true) + burn_address = insert(:address, hash: "0x0000000000000000000000000000000000000000") + + insert(:token_transfer, + from_address: insert(:address), + block: block, + block_number: block.number, + token_contract_address: token_address, + token_ids: nil + ) + + deposit_log = insert(:log, first_topic: TokenTransfer.weth_deposit_signature()) + + insert(:token_transfer, + from_address: insert(:address), + token_contract_address: token_address, + block: deposit_log.block, + transaction: deposit_log.transaction, + log_index: deposit_log.index + ) + + withdrawal_log = insert(:log, first_topic: TokenTransfer.weth_withdrawal_signature()) + + insert(:token_transfer, + from_address: insert(:address), + token_contract_address: token_address, + block: withdrawal_log.block, + transaction: withdrawal_log.transaction, + log_index: withdrawal_log.index + ) + + %{contract_address: whitelisted_token_address} = insert(:token, type: "ERC-20") + + env = Application.get_env(:explorer, Explorer.Chain.TokenTransfer) + + Application.put_env( + :explorer, + Explorer.Chain.TokenTransfer, + Keyword.put(env, :whitelisted_weth_contracts, [whitelisted_token_address |> to_string() |> String.downcase()]) + ) + + withdrawal_log = insert(:log, first_topic: TokenTransfer.weth_withdrawal_signature()) + + insert(:token_transfer, + from_address: insert(:address), + token_contract_address: whitelisted_token_address, + block: withdrawal_log.block, + transaction: withdrawal_log.transaction, + log_index: withdrawal_log.index + ) + + deposit_log = insert(:log, first_topic: TokenTransfer.weth_deposit_signature()) + + insert(:token_transfer, + from_address: insert(:address), + token_contract_address: whitelisted_token_address, + block: deposit_log.block, + transaction: deposit_log.transaction, + log_index: deposit_log.index + ) + + withdrawal_log_duplicate = insert(:log, first_topic: TokenTransfer.weth_withdrawal_signature()) + + tt_withdrawal = + insert(:token_transfer, + from_address: burn_address, + token_contract_address: whitelisted_token_address, + block: withdrawal_log_duplicate.block, + transaction: withdrawal_log_duplicate.transaction, + log_index: withdrawal_log_duplicate.index + ) + + insert(:token_transfer, + from_address: burn_address, + to_address: tt_withdrawal.to_address, + token_contract_address: whitelisted_token_address, + block: withdrawal_log_duplicate.block, + transaction: withdrawal_log_duplicate.transaction, + log_index: withdrawal_log_duplicate.index + 1, + amount: tt_withdrawal.amount + ) + + deposit_log_duplicate = insert(:log, first_topic: TokenTransfer.weth_deposit_signature()) + + tt_deposit = + insert(:token_transfer, + to_address: burn_address, + token_contract_address: whitelisted_token_address, + block: deposit_log_duplicate.block, + transaction: deposit_log_duplicate.transaction, + log_index: deposit_log_duplicate.index + ) + + insert(:token_transfer, + from_address: tt_deposit.from_address, + to_address: burn_address, + token_contract_address: whitelisted_token_address, + block: deposit_log_duplicate.block, + transaction: deposit_log_duplicate.transaction, + log_index: deposit_log_duplicate.index + 1, + amount: tt_deposit.amount + ) + + assert MigrationStatus.get_status("sanitize_incorrect_weth_transfers") == nil + + Application.put_env(:explorer, Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers, + batch_size: 1, + concurrency: 1 + ) + + SanitizeIncorrectWETHTokenTransfers.start_link([]) + Process.sleep(100) + + assert MigrationStatus.get_status("sanitize_incorrect_weth_transfers") == "completed" + + token_address_hash = token_address.hash + whitelisted_token_address_hash = whitelisted_token_address.hash + + assert [ + %{token_contract_address_hash: ^token_address_hash}, + %{token_contract_address_hash: ^whitelisted_token_address_hash}, + %{token_contract_address_hash: ^whitelisted_token_address_hash}, + %{token_contract_address_hash: ^whitelisted_token_address_hash}, + %{token_contract_address_hash: ^whitelisted_token_address_hash} + ] = transfers = Repo.all(TokenTransfer) + + withdrawal = Enum.at(transfers, 1) + deposit = Enum.at(transfers, 2) + assert withdrawal.block_hash == withdrawal_log.block_hash + assert withdrawal.transaction_hash == withdrawal_log.transaction_hash + assert withdrawal.log_index == withdrawal_log.index + + assert deposit.block_hash == deposit_log.block_hash + assert deposit.transaction_hash == deposit_log.transaction_hash + assert deposit.log_index == deposit_log.index + + withdrawal_analogue = Enum.at(transfers, 3) + deposit_analogue = Enum.at(transfers, 4) + + assert withdrawal_analogue.block_hash == withdrawal_log_duplicate.block_hash + assert withdrawal_analogue.transaction_hash == withdrawal_log_duplicate.transaction_hash + assert withdrawal_analogue.log_index == withdrawal_log_duplicate.index + 1 + + assert deposit_analogue.block_hash == deposit_log_duplicate.block_hash + assert deposit_analogue.transaction_hash == deposit_log_duplicate.transaction_hash + assert deposit_analogue.log_index == deposit_log_duplicate.index + 1 + + Application.put_env(:explorer, Explorer.Chain.TokenTransfer, env) + end + end +end diff --git a/apps/indexer/lib/indexer/transform/token_transfers.ex b/apps/indexer/lib/indexer/transform/token_transfers.ex index 2ffd90abd1..761323d1a4 100644 --- a/apps/indexer/lib/indexer/transform/token_transfers.ex +++ b/apps/indexer/lib/indexer/transform/token_transfers.ex @@ -25,10 +25,12 @@ defmodule Indexer.Transform.TokenTransfers do weth_transfers = logs |> Enum.filter(fn log -> - log.first_topic == TokenTransfer.weth_deposit_signature() || - log.first_topic == TokenTransfer.weth_withdrawal_signature() + (log.first_topic == TokenTransfer.weth_deposit_signature() || + log.first_topic == TokenTransfer.weth_withdrawal_signature()) && + TokenTransfer.whitelisted_weth_contract?(log.address_hash) end) |> Enum.reduce(initial_acc, &do_parse/2) + |> drop_repeated_token_transfers(erc20_and_erc721_token_transfers.token_transfers) erc1155_token_transfers = logs @@ -80,6 +82,33 @@ defmodule Indexer.Transform.TokenTransfers do token_transfers_from_logs_uniq end + defp drop_repeated_token_transfers(weth_acc, erc_20_721_token_transfers) do + key_from_tt = fn tt -> + {tt.block_hash, tt.transaction_hash, tt.token_contract_address_hash, tt.to_address_hash, tt.from_address_hash, + tt.amount} + end + + deposit_withdrawal_like_transfers = + Enum.reduce(erc_20_721_token_transfers, %{}, fn token_transfer, acc -> + if token_transfer.token_type == "ERC-20" and + (token_transfer.from_address_hash == burn_address_hash_string() or + token_transfer.to_address_hash == burn_address_hash_string()) do + Map.put(acc, key_from_tt.(token_transfer), true) + else + acc + end + end) + + %{token_transfers: weth_token_transfer} = weth_acc + + weth_token_transfer_updated = + Enum.reject(weth_token_transfer, fn weth_tt -> + deposit_withdrawal_like_transfers[key_from_tt.(weth_tt)] + end) + + Map.put(weth_acc, :token_transfers, weth_token_transfer_updated) + end + defp sanitize_weth_transfers(total_tokens, total_transfers, weth_transfers) do existing_token_types_map = total_tokens diff --git a/apps/indexer/test/indexer/transform/token_transfers_test.exs b/apps/indexer/test/indexer/transform/token_transfers_test.exs index f8be8358ab..f25c207681 100644 --- a/apps/indexer/test/indexer/transform/token_transfers_test.exs +++ b/apps/indexer/test/indexer/transform/token_transfers_test.exs @@ -137,7 +137,19 @@ defmodule Indexer.Transform.TokenTransfersTest do ] } + env = Application.get_env(:explorer, Explorer.Chain.TokenTransfer) + + Application.put_env( + :explorer, + Explorer.Chain.TokenTransfer, + Keyword.put(env, :whitelisted_weth_contracts, [ + weth_deposit_log.address_hash |> to_string() |> String.downcase() + ]) + ) + assert TokenTransfers.parse(logs) == expected + + Application.put_env(:explorer, Explorer.Chain.TokenTransfer, env) end test "parses ERC-721 transfer with addresses in data field" do @@ -435,6 +447,147 @@ defmodule Indexer.Transform.TokenTransfersTest do ] } end + + test "Filters WETH transfers from not whitelisted tokens" do + logs = [ + %{ + address_hash: "0x0BE9e53fd7EDaC9F859882AfdDa116645287C629", + block_number: 23_704_638, + block_hash: "0x8f61c99b0dd1196714ffda5bf979a282e6a62fdd3cff25c291284e6b57de2106", + data: "0x00000000000000000000000000000000000000000000002be19edfcf6b480000", + first_topic: "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + second_topic: "0x000000000000000000000000fb76e9e7d88e308ab530330ed90e84a952570319", + third_topic: nil, + fourth_topic: nil, + index: 1, + transaction_hash: "0x185889bc91372106ecf114a4e23f4ee615e131ae3e698078bd5d2ed7e3f55a49" + }, + %{ + address_hash: "0x0BE9e53fd7EDaC9F859882AfdDa116645287C629", + block_number: 23_704_608, + block_hash: "0x5a5e69984f78d65fc6d92e18058d21a9b114f1d56d06ca7aa017b3d87bf0491a", + data: "0x00000000000000000000000000000000000000000000000000e1315e1ebd28e8", + first_topic: "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + second_topic: "0x000000000000000000000000e3f85aad0c8dd7337427b9df5d0fb741d65eeeb5", + third_topic: nil, + fourth_topic: nil, + index: 1, + transaction_hash: "0x07510dbfddbac9064f7d607c2d9a14aa26fa19cdfcd578c0b585ff2395df543f" + } + ] + + expected = %{token_transfers: [], tokens: []} + + assert TokenTransfers.parse(logs) == expected + end + + test "Filters duplicates WETH transfers" do + [log_1, _weth_deposit_log, log_2, _weth_withdrawal_log] = + logs = [ + %{ + address_hash: "0x0BE9e53fd7EDaC9F859882AfdDa116645287C629", + block_number: 23_704_638, + block_hash: "0x79594150677f083756a37eee7b97ed99ab071f502104332cb3835bac345711ca", + data: "0x00000000000000000000000000000000000000000000002be19edfcf6b480000", + first_topic: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + fourth_topic: nil, + index: 1, + second_topic: "0x0000000000000000000000000000000000000000000000000000000000000000", + third_topic: "0x000000000000000000000000fb76e9e7d88e308ab530330ed90e84a952570319", + transaction_hash: "0x4011d9a930a3da620321589a54dc0ca3b88216b4886c7a7c3aaad1fb17702d35" + }, + %{ + address_hash: "0x0BE9e53fd7EDaC9F859882AfdDa116645287C629", + block_number: 23_704_638, + block_hash: "0x79594150677f083756a37eee7b97ed99ab071f502104332cb3835bac345711ca", + data: "0x00000000000000000000000000000000000000000000002be19edfcf6b480000", + first_topic: "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + second_topic: "0x000000000000000000000000fb76e9e7d88e308ab530330ed90e84a952570319", + third_topic: nil, + fourth_topic: nil, + index: 2, + transaction_hash: "0x4011d9a930a3da620321589a54dc0ca3b88216b4886c7a7c3aaad1fb17702d35" + }, + %{ + address_hash: "0xf2eec76e45b328df99a34fa696320a262cb92154", + block_number: 3_530_917, + block_hash: "0x5a5e69984f78d65fc6d92e18058d21a9b114f1d56d06ca7aa017b3d87bf0491a", + data: "0x00000000000000000000000000000000000000000000000000e1315e1ebd28e8", + first_topic: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + fourth_topic: nil, + index: 8, + second_topic: "0x000000000000000000000000e3f85aad0c8dd7337427b9df5d0fb741d65eeeb5", + third_topic: "0x0000000000000000000000000000000000000000000000000000000000000000", + transaction_hash: "0x185889bc91372106ecf114a4e23f4ee615e131ae3e698078bd5d2ed7e3f55a49" + }, + %{ + address_hash: "0xf2eec76e45b328df99a34fa696320a262cb92154", + block_number: 3_530_917, + block_hash: "0x5a5e69984f78d65fc6d92e18058d21a9b114f1d56d06ca7aa017b3d87bf0491a", + data: "0x00000000000000000000000000000000000000000000000000e1315e1ebd28e8", + first_topic: "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + second_topic: "0x000000000000000000000000e3f85aad0c8dd7337427b9df5d0fb741d65eeeb5", + third_topic: nil, + fourth_topic: nil, + index: 1, + transaction_hash: "0x185889bc91372106ecf114a4e23f4ee615e131ae3e698078bd5d2ed7e3f55a49" + } + ] + + expected = %{ + tokens: [ + %{ + contract_address_hash: log_2.address_hash, + type: "ERC-20" + }, + %{ + contract_address_hash: log_1.address_hash, + type: "ERC-20" + } + ], + token_transfers: [ + %{ + token_ids: nil, + amount: Decimal.new(63_386_150_072_297_704), + block_number: log_2.block_number, + log_index: log_2.index, + from_address_hash: truncated_hash(log_2.second_topic), + to_address_hash: truncated_hash(log_2.third_topic), + token_contract_address_hash: log_2.address_hash, + transaction_hash: log_2.transaction_hash, + token_type: "ERC-20", + block_hash: log_2.block_hash + }, + %{ + block_number: log_1.block_number, + log_index: log_1.index, + from_address_hash: truncated_hash(log_1.second_topic), + to_address_hash: truncated_hash(log_1.third_topic), + token_contract_address_hash: log_1.address_hash, + token_ids: nil, + transaction_hash: log_1.transaction_hash, + token_type: "ERC-20", + block_hash: log_1.block_hash, + amount: Decimal.new(809_467_672_956_315_893_760) + } + ] + } + + env = Application.get_env(:explorer, Explorer.Chain.TokenTransfer) + + Application.put_env( + :explorer, + Explorer.Chain.TokenTransfer, + Keyword.put(env, :whitelisted_weth_contracts, [ + log_1.address_hash |> to_string() |> String.downcase(), + log_2.address_hash |> to_string() |> String.downcase() + ]) + ) + + assert TokenTransfers.parse(logs) == expected + + Application.put_env(:explorer, Explorer.Chain.TokenTransfer, env) + end end defp truncated_hash("0x000000000000000000000000" <> rest) do diff --git a/config/runtime.exs b/config/runtime.exs index 72c02fb50b..833ed58e4e 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -569,6 +569,10 @@ config :explorer, Explorer.Migrator.SanitizeIncorrectNFTTokenTransfers, batch_size: ConfigHelper.parse_integer_env_var("SANITIZE_INCORRECT_NFT_BATCH_SIZE", 100), concurrency: ConfigHelper.parse_integer_env_var("SANITIZE_INCORRECT_NFT_CONCURRENCY", 1) +config :explorer, Explorer.Migrator.SanitizeIncorrectWETHTokenTransfers, + batch_size: ConfigHelper.parse_integer_env_var("SANITIZE_INCORRECT_WETH_BATCH_SIZE", 100), + concurrency: ConfigHelper.parse_integer_env_var("SANITIZE_INCORRECT_WETH_CONCURRENCY", 1) + config :explorer, Explorer.Chain.BridgedToken, eth_omni_bridge_mediator: System.get_env("BRIDGED_TOKENS_ETH_OMNI_BRIDGE_MEDIATOR"), bsc_omni_bridge_mediator: System.get_env("BRIDGED_TOKENS_BSC_OMNI_BRIDGE_MEDIATOR"), @@ -579,6 +583,9 @@ config :explorer, Explorer.Chain.BridgedToken, config :explorer, Explorer.Utility.MissingBalanceOfToken, window_size: ConfigHelper.parse_integer_env_var("MISSING_BALANCE_OF_TOKENS_WINDOW_SIZE", 100) +config :explorer, Explorer.Chain.TokenTransfer, + whitelisted_weth_contracts: ConfigHelper.parse_list_env_var("WHITELISTED_WETH_CONTRACTS", "") + ############### ### Indexer ### ###############