diff --git a/CHANGELOG.md b/CHANGELOG.md index a66d63fdb3..7e3a90828d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [#1742](https://github.com/poanetwork/blockscout/pull/1742) - Support RSK - [#1777](https://github.com/poanetwork/blockscout/pull/1777) - show ERC-20 token transfer info on transaction page - [#1770](https://github.com/poanetwork/blockscout/pull/1770) - set a websocket keepalive from config +- [#1789](https://github.com/poanetwork/blockscout/pull/1789) - add ERC-721 info to transaction overview page ### Fixes 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 98acd3b3e6..a3e4490910 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 @@ -138,9 +138,10 @@ - <% token_transfer = assigns[:token_transfers] && erc20_token_transfer(@transaction, @token_transfers) %> - <%= if token_transfer do %> -
+ <%= cond do %> + <% erc20_token_transfer = assigns[:token_transfers] && erc20_token_transfer(@transaction, @token_transfers) -> %> + +
@@ -148,15 +149,32 @@

- <%= token_transfer_amount(token_transfer) %> - <%= link(token_symbol(token_transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, token_transfer.token.contract_address_hash)) %> + <%= token_transfer_amount(erc20_token_transfer) %> + <%= link(token_symbol(erc20_token_transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, erc20_token_transfer.token.contract_address_hash)) %>

-
- <% else %> -
+
+ <% erc721_token_transfer = assigns[:token_transfers] && erc721_token_transfer(@transaction, @token_transfers) -> %> + +
+ +
+
+

<%= gettext "ERC-721" %> <%= gettext "Token Transfer" %>

+
+

+ + <%= token_transfer_amount(erc721_token_transfer) %> + <%= link(token_symbol(erc721_token_transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, erc721_token_transfer.token.contract_address_hash)) %> + +

+
+
+
+ <% true -> %> +
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 a6f58ac33e..8fa133550f 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 @@ -48,30 +48,70 @@ defmodule BlockScoutWeb.TransactionView do {unquote(TokenTransfer.transfer_function_signature()) <> params, ^zero_wei} -> types = [:address, {:uint, 256}] - try do - [address, value] = - params - |> Base.decode16!(case: :mixed) - |> TypeDecoder.decode_raw(types) + [address, value] = decode_params(params, types) - decimal_value = Decimal.new(value) + 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) - rescue - _ -> nil - end + Enum.find(token_transfers, fn token_transfer -> + token_transfer.to_address_hash.bytes == address && token_transfer.amount == decimal_value + end) _ -> nil end + rescue + _ -> nil 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 @@ -298,4 +338,10 @@ defmodule BlockScoutWeb.TransactionView do defp tab_name(["token_transfers"]), do: gettext("Token Transfers") defp tab_name(["internal_transactions"]), do: gettext("Internal Transactions") defp tab_name(["logs"]), do: gettext("Logs") + + defp decode_params(params, types) do + params + |> Base.decode16!(case: :mixed) + |> TypeDecoder.decode_raw(types) + end end diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 7010a68126..55621eb6ef 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:169 +#: lib/block_scout_web/views/transaction_view.ex:209 msgid "(Awaiting internal transactions for status)" msgstr "" @@ -278,12 +278,12 @@ msgid "Contract Address Pending" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:246 +#: lib/block_scout_web/views/transaction_view.ex:286 msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:245 +#: lib/block_scout_web/views/transaction_view.ex:285 msgid "Contract Creation" msgstr "" @@ -377,12 +377,12 @@ msgid "Error trying to fetch balances." msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:173 +#: lib/block_scout_web/views/transaction_view.ex:213 msgid "Error: %{reason}" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:171 +#: lib/block_scout_web/views/transaction_view.ex:211 msgid "Error: (Awaiting internal transactions for reason)" msgstr "" @@ -392,7 +392,7 @@ msgstr "" #: lib/block_scout_web/templates/layout/app.html.eex:66 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:27 -#: lib/block_scout_web/templates/transaction/overview.html.eex:163 +#: lib/block_scout_web/templates/transaction/overview.html.eex:181 #: lib/block_scout_web/views/wei_helpers.ex:72 msgid "Ether" msgstr "" @@ -431,7 +431,7 @@ msgid "GET" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:176 +#: lib/block_scout_web/templates/transaction/overview.html.eex:194 msgid "Gas" msgstr "" @@ -495,7 +495,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:43 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10 #: lib/block_scout_web/views/address_view.ex:295 -#: lib/block_scout_web/views/transaction_view.ex:299 +#: lib/block_scout_web/views/transaction_view.ex:339 msgid "Internal Transactions" msgstr "" @@ -513,7 +513,7 @@ msgid "Less than" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:188 +#: lib/block_scout_web/templates/transaction/overview.html.eex:206 msgid "Limit" msgstr "" @@ -521,7 +521,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:21 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:48 #: lib/block_scout_web/templates/transaction_log/index.html.eex:10 -#: lib/block_scout_web/views/transaction_view.ex:300 +#: lib/block_scout_web/views/transaction_view.ex:340 msgid "Logs" msgstr "" @@ -533,7 +533,7 @@ msgid "Market Cap" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:154 +#: lib/block_scout_web/views/transaction_view.ex:194 msgid "Max of" msgstr "" @@ -661,8 +661,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 -#: lib/block_scout_web/views/transaction_view.ex:168 -#: lib/block_scout_web/views/transaction_view.ex:202 +#: lib/block_scout_web/views/transaction_view.ex:208 +#: lib/block_scout_web/views/transaction_view.ex:242 msgid "Pending" msgstr "" @@ -762,7 +762,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8 -#: lib/block_scout_web/views/transaction_view.ex:170 +#: lib/block_scout_web/views/transaction_view.ex:210 msgid "Success" msgstr "" @@ -872,9 +872,10 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/templates/transaction/overview.html.eex:147 +#: lib/block_scout_web/templates/transaction/overview.html.eex:148 +#: lib/block_scout_web/templates/transaction/overview.html.eex:165 #: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/views/transaction_view.ex:244 +#: lib/block_scout_web/views/transaction_view.ex:284 msgid "Token Transfer" msgstr "" @@ -886,7 +887,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:36 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10 #: lib/block_scout_web/views/tokens/overview_view.ex:35 -#: lib/block_scout_web/views/transaction_view.ex:298 +#: lib/block_scout_web/views/transaction_view.ex:338 msgid "Token Transfers" msgstr "" @@ -927,7 +928,7 @@ msgid "Total transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:247 +#: lib/block_scout_web/views/transaction_view.ex:287 msgid "Transaction" msgstr "" @@ -994,7 +995,7 @@ msgid "Unique Token" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:181 +#: lib/block_scout_web/templates/transaction/overview.html.eex:199 msgid "Used" msgstr "" @@ -1015,7 +1016,7 @@ msgid "Validations" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:163 +#: lib/block_scout_web/templates/transaction/overview.html.eex:181 msgid "Value" msgstr "" @@ -1735,6 +1736,11 @@ msgid "Optimization runs" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:147 +#: lib/block_scout_web/templates/transaction/overview.html.eex:148 msgid "ERC-20" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/transaction/overview.html.eex:165 +msgid "ERC-721" +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 8a18c60018..7d7554d7d7 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 @@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:169 +#: lib/block_scout_web/views/transaction_view.ex:209 msgid "(Awaiting internal transactions for status)" msgstr "" @@ -278,12 +278,12 @@ msgid "Contract Address Pending" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:246 +#: lib/block_scout_web/views/transaction_view.ex:286 msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:245 +#: lib/block_scout_web/views/transaction_view.ex:285 msgid "Contract Creation" msgstr "" @@ -377,12 +377,12 @@ msgid "Error trying to fetch balances." msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:173 +#: lib/block_scout_web/views/transaction_view.ex:213 msgid "Error: %{reason}" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:171 +#: lib/block_scout_web/views/transaction_view.ex:211 msgid "Error: (Awaiting internal transactions for reason)" msgstr "" @@ -392,7 +392,7 @@ msgstr "" #: lib/block_scout_web/templates/layout/app.html.eex:66 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:27 -#: lib/block_scout_web/templates/transaction/overview.html.eex:163 +#: lib/block_scout_web/templates/transaction/overview.html.eex:181 #: lib/block_scout_web/views/wei_helpers.ex:72 msgid "Ether" msgstr "POA" @@ -431,7 +431,7 @@ msgid "GET" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:176 +#: lib/block_scout_web/templates/transaction/overview.html.eex:194 msgid "Gas" msgstr "" @@ -495,7 +495,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:43 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10 #: lib/block_scout_web/views/address_view.ex:295 -#: lib/block_scout_web/views/transaction_view.ex:299 +#: lib/block_scout_web/views/transaction_view.ex:339 msgid "Internal Transactions" msgstr "" @@ -513,7 +513,7 @@ msgid "Less than" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:188 +#: lib/block_scout_web/templates/transaction/overview.html.eex:206 msgid "Limit" msgstr "" @@ -521,7 +521,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:21 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:48 #: lib/block_scout_web/templates/transaction_log/index.html.eex:10 -#: lib/block_scout_web/views/transaction_view.ex:300 +#: lib/block_scout_web/views/transaction_view.ex:340 msgid "Logs" msgstr "" @@ -533,7 +533,7 @@ msgid "Market Cap" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:154 +#: lib/block_scout_web/views/transaction_view.ex:194 msgid "Max of" msgstr "" @@ -661,8 +661,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 -#: lib/block_scout_web/views/transaction_view.ex:168 -#: lib/block_scout_web/views/transaction_view.ex:202 +#: lib/block_scout_web/views/transaction_view.ex:208 +#: lib/block_scout_web/views/transaction_view.ex:242 msgid "Pending" msgstr "" @@ -762,7 +762,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8 -#: lib/block_scout_web/views/transaction_view.ex:170 +#: lib/block_scout_web/views/transaction_view.ex:210 msgid "Success" msgstr "" @@ -872,9 +872,10 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/templates/transaction/overview.html.eex:147 +#: lib/block_scout_web/templates/transaction/overview.html.eex:148 +#: lib/block_scout_web/templates/transaction/overview.html.eex:165 #: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/views/transaction_view.ex:244 +#: lib/block_scout_web/views/transaction_view.ex:284 msgid "Token Transfer" msgstr "" @@ -886,7 +887,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:36 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10 #: lib/block_scout_web/views/tokens/overview_view.ex:35 -#: lib/block_scout_web/views/transaction_view.ex:298 +#: lib/block_scout_web/views/transaction_view.ex:338 msgid "Token Transfers" msgstr "" @@ -927,7 +928,7 @@ msgid "Total transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:247 +#: lib/block_scout_web/views/transaction_view.ex:287 msgid "Transaction" msgstr "" @@ -994,7 +995,7 @@ msgid "Unique Token" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:181 +#: lib/block_scout_web/templates/transaction/overview.html.eex:199 msgid "Used" msgstr "" @@ -1015,7 +1016,7 @@ msgid "Validations" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:163 +#: lib/block_scout_web/templates/transaction/overview.html.eex:181 msgid "Value" msgstr "" @@ -1735,6 +1736,11 @@ msgid "Optimization runs" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/overview.html.eex:147 +#: lib/block_scout_web/templates/transaction/overview.html.eex:148 msgid "ERC-20" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/transaction/overview.html.eex:165 +msgid "ERC-721" +msgstr "" 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 2a3e5492ed..e8efeff6a0 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,6 +47,30 @@ 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)