diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex index 7c22762e49..81d3a41706 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex @@ -169,39 +169,22 @@ - <%= cond do %> - <% erc20_token_transfer = assigns[:token_transfers] && erc20_token_transfer(@transaction, @token_transfers) -> %> - + <%= case token_transfer_type(@transaction) do %> + <% {type, token_transfer} -> %>
+
data-usd-exchange-rate=<%= @exchange_rate.usd_value %>>
<% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex index 418a7161de..026147ac3e 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex @@ -1,12 +1,11 @@ defmodule BlockScoutWeb.TransactionView do use BlockScoutWeb, :view - alias ABI.TypeDecoder alias BlockScoutWeb.{AddressView, BlockView, TabHelpers} alias Cldr.Number alias Explorer.Chain alias Explorer.Chain.Block.Reward - alias Explorer.Chain.{Address, Block, InternalTransaction, TokenTransfer, Transaction, Wei} + alias Explorer.Chain.{Address, Block, InternalTransaction, Transaction, Wei} alias Explorer.ExchangeRates.Token alias Timex.Duration @@ -33,85 +32,10 @@ defmodule BlockScoutWeb.TransactionView do def value_transfer?(_), do: false - def erc20_token_transfer( - %Transaction{ - status: :ok, - created_contract_address_hash: nil, - input: input, - value: value - }, - token_transfers - ) do - zero_wei = %Wei{value: Decimal.new(0)} - - case {to_string(input), value} do - {unquote(TokenTransfer.transfer_function_signature()) <> params, ^zero_wei} -> - types = [:address, {:uint, 256}] - - [address, value] = decode_params(params, types) - - decimal_value = Decimal.new(value) - - Enum.find(token_transfers, fn token_transfer -> - token_transfer.to_address_hash.bytes == address && token_transfer.amount == decimal_value - end) - - _ -> - nil - end - rescue - _ -> nil + def token_transfer_type(transaction) do + Chain.transaction_token_transfer_type(transaction) end - def erc20_token_transfer(_, _) do - nil - end - - def erc721_token_transfer( - %Transaction{ - status: :ok, - created_contract_address_hash: nil, - input: input, - value: value - }, - token_transfers - ) do - zero_wei = %Wei{value: Decimal.new(0)} - - # https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721.sol#L35 - {from_address, to_address} = - case {to_string(input), value} do - # transferFrom(address,address,uint256) - {"0x23b872dd" <> params, ^zero_wei} -> - types = [:address, :address, {:uint, 256}] - [from_address, to_address, _value] = decode_params(params, types) - {from_address, to_address} - - # safeTransferFrom(address,address,uint256) - {"0x42842e0e" <> params, ^zero_wei} -> - types = [:address, :address, {:uint, 256}] - [from_address, to_address, _value] = decode_params(params, types) - {from_address, to_address} - - # safeTransferFrom(address,address,uint256,bytes) - {"0xb88d4fde" <> params, ^zero_wei} -> - types = [:address, :address, {:uint, 256}, :bytes] - [from_address, to_address, _value, _data] = decode_params(params, types) - {from_address, to_address} - - _ -> - nil - end - - Enum.find(token_transfers, fn token_transfer -> - token_transfer.from_address_hash.bytes == from_address && token_transfer.to_address_hash.bytes == to_address - end) - rescue - _ -> nil - end - - def erc721_token_transfer(_, _), do: nil - def processing_time_duration(%Transaction{block: nil}) do :pending end @@ -339,10 +263,4 @@ defmodule BlockScoutWeb.TransactionView do defp tab_name(["internal_transactions"]), do: gettext("Internal Transactions") defp tab_name(["logs"]), do: gettext("Logs") defp tab_name(["raw_trace"]), do: gettext("Raw Trace") - - defp decode_params(params, types) do - params - |> Base.decode16!(case: :mixed) - |> TypeDecoder.decode_raw(types) - end end diff --git a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs index e8efeff6a0..2a3e5492ed 100644 --- a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs @@ -47,30 +47,6 @@ defmodule BlockScoutWeb.TransactionViewTest do end end - describe "erc721_token_transfer/2" do - test "finds token transfer" do - from_address_hash = "0x7a30272c902563b712245696f0a81c5a0e45ddc8" - to_address_hash = "0xb544cead8b660aae9f2e37450f7be2ffbc501793" - from_address = insert(:address, hash: from_address_hash) - to_address = insert(:address, hash: to_address_hash) - block = insert(:block) - - transaction = - insert(:transaction, - input: - "0x23b872dd0000000000000000000000007a30272c902563b712245696f0a81c5a0e45ddc8000000000000000000000000b544cead8b660aae9f2e37450f7be2ffbc5017930000000000000000000000000000000000000000000000000000000000000002", - value: Decimal.new(0), - created_contract_address_hash: nil - ) - |> with_block(block, status: :ok) - - token_transfer = - insert(:token_transfer, from_address: from_address, to_address: to_address, transaction: transaction) - - assert TransactionView.erc721_token_transfer(transaction, [token_transfer]) == token_transfer - end - end - describe "processing_time_duration/2" do test "returns :pending if the transaction has no block" do transaction = build(:transaction, block: nil) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 12090f37de..f18a1b811c 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -2833,10 +2833,7 @@ defmodule Explorer.Chain do ) do zero_wei = %Wei{value: Decimal.new(0)} - transaction = - if Ecto.assoc_loaded?(transaction.token_transfers), - do: transaction, - else: Repo.preload(transaction, :token_transfers) + transaction = Repo.preload(transaction, token_transfers: :token) # https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721.sol#L35 case {to_string(input), value} do @@ -2890,17 +2887,16 @@ defmodule Explorer.Chain do end defp find_erc721_or_erc20_token_transfer(token_transfers, {address, decimal_value}) do - IO.inspect({address, decimal_value}) - token_transfer = Enum.find(token_transfers, fn token_transfer -> - token_transfer.to_address_hash.bytes == address && token_transfer.amount == decimal_value + token_transfer.to_address_hash.bytes == address && + (token_transfer.amount == decimal_value || token_transfer.token_id) end) if token_transfer do - case token_from_address_hash(token_transfer.token_contract_address_hash) do - {:ok, %Token{type: "ERC-20"}} -> {:erc20, token_transfer} - {:ok, %Token{type: "ERC-721"}} -> {:erc721, token_transfer} + case token_transfer.token do + %Token{type: "ERC-20"} -> {:erc20, token_transfer} + %Token{type: "ERC-721"} -> {:erc721, token_transfer} _ -> nil end end