+
+ <%= gettext "Show Raw Data"%>
+
+
+
+ ">
+ ×
+
<%= log.data %>
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex b/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex
new file mode 100644
index 0000000000..31c4aa1140
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex
@@ -0,0 +1,115 @@
+defmodule BlockScoutWeb.ABIEncodedValueView do
+ @moduledoc """
+ Renders a decoded value that is encoded according to an ABI.
+
+ Does not leverage an eex template because it renders formatted
+ values via `
` tags, and that is hard to do in an eex template.
+ """
+ use BlockScoutWeb, :view
+
+ alias ABI.FunctionSelector
+ alias Phoenix.HTML
+
+ require Logger
+
+ def value_html(type, value) do
+ decoded_type = FunctionSelector.decode_type(type)
+
+ do_value_html(decoded_type, value)
+ rescue
+ exception ->
+ Logger.warn(fn ->
+ ["Error determining value html for #{inspect(type)}: ", Exception.format(:error, exception)]
+ end)
+
+ :error
+ end
+
+ def copy_text(type, value) do
+ decoded_type = FunctionSelector.decode_type(type)
+
+ do_copy_text(decoded_type, value)
+ rescue
+ exception ->
+ Logger.warn(fn ->
+ ["Error determining copy text for #{inspect(type)}: ", Exception.format(:error, exception)]
+ end)
+
+ :error
+ end
+
+ defp do_copy_text({:bytes, _type}, value) do
+ hex(value)
+ end
+
+ defp do_copy_text({:array, type, _}, value) do
+ do_copy_text({:array, type}, value)
+ end
+
+ defp do_copy_text({:array, type}, value) do
+ values =
+ value
+ |> Enum.map(&do_copy_text(type, &1))
+ |> Enum.intersperse(", ")
+
+ ~E|[<%= values %>]|
+ end
+
+ defp do_copy_text(_, {:dynamic, value}) do
+ hex(value)
+ end
+
+ defp do_copy_text(type, value) when type in [:bytes, :address] do
+ hex(value)
+ end
+
+ defp do_copy_text(_type, value) do
+ to_string(value)
+ end
+
+ defp do_value_html(type, value, depth \\ 0)
+
+ defp do_value_html({:bytes, _}, value, depth) do
+ do_value_html(:bytes, value, depth)
+ end
+
+ defp do_value_html({:array, type, _}, value, depth) do
+ do_value_html({:array, type}, value, depth)
+ end
+
+ defp do_value_html({:array, type}, value, depth) do
+ values =
+ Enum.map(value, fn inner_value ->
+ do_value_html(type, inner_value, depth + 1)
+ end)
+
+ spacing = String.duplicate(" ", depth * 2)
+ delimited = Enum.intersperse(values, ",\n")
+
+ ~E|<%= spacing %>[<%= "\n" %><%= delimited %><%= "\n" %><%= spacing %>]|
+ end
+
+ defp do_value_html(type, value, depth) do
+ spacing = String.duplicate(" ", depth * 2)
+ ~E|<%= spacing %><%=base_value_html(type, value)%>|
+ [spacing, base_value_html(type, value)]
+ end
+
+ defp base_value_html(_, {:dynamic, value}) do
+ hex(value)
+ end
+
+ defp base_value_html(:address, value) do
+ address = hex(value)
+
+ ~E|<%= address %> |
+ end
+
+ defp base_value_html(:bytes, value) do
+ hex(value)
+ end
+
+ defp base_value_html(_, value), do: HTML.html_escape(value)
+
+ defp hex(value), do: "0x" <> Base.encode16(value, case: :lower)
+end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex b/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex
index 96cf62fe9a..50d406433c 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex
@@ -1,4 +1,10 @@
defmodule BlockScoutWeb.TransactionLogView do
use BlockScoutWeb, :view
@dialyzer :no_match
+
+ alias Explorer.Chain.Log
+
+ def decode(log, transaction) do
+ Log.decode(log, transaction)
+ end
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 6f630668b4..3fc4ee279e 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
@@ -20,6 +20,12 @@ defmodule BlockScoutWeb.TransactionView do
def block_timestamp(%Transaction{block_number: nil, inserted_at: time}), do: time
def block_timestamp(%Transaction{block: %Block{timestamp: time}}), do: time
+ def value_transfer?(%Transaction{input: %{bytes: bytes}}) when bytes in [<<>>, nil] do
+ true
+ end
+
+ def value_transfer?(_), do: false
+
def confirmations(%Transaction{block: block}, named_arguments) when is_list(named_arguments) do
case block do
nil -> 0
@@ -73,6 +79,10 @@ defmodule BlockScoutWeb.TransactionView do
Cldr.Number.to_string!(gas)
end
+ def should_decode?(transaction) do
+ contract_creation?(transaction) || value_transfer?(transaction)
+ end
+
def decoded_input_data(transaction) do
Transaction.decoded_input_data(transaction)
end
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index c634ffcb5b..9ae3578b23 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -56,7 +56,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:58
+#: lib/block_scout_web/views/transaction_view.ex:64
msgid "(Awaiting internal transactions for status)"
msgstr ""
@@ -151,7 +151,7 @@ msgid "Block %{block_number} - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:59
+#: lib/block_scout_web/templates/transaction/overview.html.eex:60
msgid "Block Confirmations"
msgstr ""
@@ -166,7 +166,7 @@ msgid "Block Mined, awaiting import..."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:45
+#: lib/block_scout_web/templates/transaction/overview.html.eex:46
msgid "Block Number"
msgstr ""
@@ -218,6 +218,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:82
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:84
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:92
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:94
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:133
msgid "Close"
msgstr ""
@@ -283,12 +285,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:131
+#: lib/block_scout_web/views/transaction_view.ex:141
msgid "Contract Call"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:130
+#: lib/block_scout_web/views/transaction_view.ex:140
msgid "Contract Creation"
msgstr ""
@@ -329,13 +331,13 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
-#: lib/block_scout_web/templates/transaction/overview.html.eex:10
+#: lib/block_scout_web/templates/transaction/overview.html.eex:11
msgid "Copy Transaction Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
-#: lib/block_scout_web/templates/transaction/overview.html.eex:10
+#: lib/block_scout_web/templates/transaction/overview.html.eex:11
msgid "Copy Txn Hash"
msgstr ""
@@ -355,7 +357,9 @@ msgid "Curl"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:54
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:33
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:60
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:124
msgid "Data"
msgstr ""
@@ -392,12 +396,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:62
+#: lib/block_scout_web/views/transaction_view.ex:68
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:60
+#: lib/block_scout_web/views/transaction_view.ex:66
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@@ -406,7 +410,7 @@ msgstr ""
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:16
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:19
#: lib/block_scout_web/templates/transaction/_tile.html.eex:26
-#: lib/block_scout_web/templates/transaction/overview.html.eex:182
+#: lib/block_scout_web/templates/transaction/overview.html.eex:110
#: lib/block_scout_web/views/wei_helpers.ex:72
msgid "Ether"
msgstr ""
@@ -445,7 +449,7 @@ msgid "GET"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:195
+#: lib/block_scout_web/templates/transaction/overview.html.eex:123
msgid "Gas"
msgstr ""
@@ -489,9 +493,7 @@ msgid "Indexing Tokens"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:81
-#: lib/block_scout_web/templates/transaction/overview.html.eex:88
-#: lib/block_scout_web/templates/transaction/overview.html.eex:95
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:3
msgid "Input"
msgstr ""
@@ -510,7 +512,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:213
-#: lib/block_scout_web/views/transaction_view.ex:180
+#: lib/block_scout_web/views/transaction_view.ex:190
msgid "Internal Transactions"
msgstr ""
@@ -528,7 +530,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:207
+#: lib/block_scout_web/templates/transaction/overview.html.eex:135
msgid "Limit"
msgstr ""
@@ -536,7 +538,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:181
+#: lib/block_scout_web/views/transaction_view.ex:191
msgid "Logs"
msgstr ""
@@ -548,7 +550,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:49
+#: lib/block_scout_web/views/transaction_view.ex:55
msgid "Max of"
msgstr ""
@@ -589,6 +591,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:29
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:31
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:57
msgid "Name"
msgstr ""
@@ -600,7 +604,7 @@ msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:23
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:74
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:151
msgid "Newer"
msgstr ""
@@ -623,7 +627,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:69
-#: lib/block_scout_web/templates/transaction/overview.html.eex:66
+#: lib/block_scout_web/templates/transaction/overview.html.eex:67
msgid "Nonce"
msgstr ""
@@ -682,9 +686,9 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
-#: lib/block_scout_web/templates/transaction/overview.html.eex:54
-#: lib/block_scout_web/views/transaction_view.ex:57
-#: lib/block_scout_web/views/transaction_view.ex:87
+#: lib/block_scout_web/templates/transaction/overview.html.eex:55
+#: lib/block_scout_web/views/transaction_view.ex:63
+#: lib/block_scout_web/views/transaction_view.ex:97
msgid "Pending"
msgstr ""
@@ -789,14 +793,14 @@ msgid "Showing 250 addresses of"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:59
+#: lib/block_scout_web/views/transaction_view.ex:65
msgid "Success"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
-#: lib/block_scout_web/templates/transaction/overview.html.eex:71
+#: lib/block_scout_web/templates/transaction/overview.html.eex:72
msgid "TX Fee"
msgstr ""
@@ -822,7 +826,7 @@ msgid "There are no internal transactions for this transaction."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:68
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:145
msgid "There are no logs for this transaction."
msgstr ""
@@ -862,7 +866,7 @@ msgid "There are no transfers for this Token."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:23
+#: lib/block_scout_web/templates/transaction/overview.html.eex:24
msgid "This transaction is pending confirmation."
msgstr ""
@@ -900,7 +904,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
-#: lib/block_scout_web/views/transaction_view.ex:129
+#: lib/block_scout_web/views/transaction_view.ex:139
msgid "Token Transfer"
msgstr ""
@@ -912,7 +916,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:179
+#: lib/block_scout_web/views/transaction_view.ex:189
msgid "Token Transfers"
msgstr ""
@@ -934,7 +938,7 @@ msgid "Top Accounts - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:26
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:88
msgid "Topics"
msgstr ""
@@ -954,7 +958,7 @@ msgid "Total transactions"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:132
+#: lib/block_scout_web/views/transaction_view.ex:142
msgid "Transaction"
msgstr ""
@@ -970,7 +974,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:14
-#: lib/block_scout_web/templates/transaction/overview.html.eex:15
+#: lib/block_scout_web/templates/transaction/overview.html.eex:16
msgid "Transaction Details"
msgstr ""
@@ -1023,7 +1027,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:200
+#: lib/block_scout_web/templates/transaction/overview.html.eex:128
msgid "Used"
msgstr ""
@@ -1044,7 +1048,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:182
+#: lib/block_scout_web/templates/transaction/overview.html.eex:110
msgid "Value"
msgstr ""
@@ -1228,22 +1232,15 @@ msgid "This API is provided for developers transitioning their applications from
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:153
+#: lib/block_scout_web/templates/transaction/overview.html.eex:80
msgid "Raw Input"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:156
+#: lib/block_scout_web/templates/transaction/overview.html.eex:83
msgid "Show Raw Input"
msgstr ""
-#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:130
-#: lib/block_scout_web/templates/transaction/overview.html.eex:140
-#: lib/block_scout_web/templates/transaction/overview.html.eex:164
-msgid "copy"
-msgstr ""
-
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "Error trying to fetch transactions."
@@ -1323,3 +1320,88 @@ msgstr ""
#: lib/block_scout_web/views/internal_transaction_view.ex:24
msgid "Static Call"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:26
+msgid "Decoded"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:59
+msgid "Indexed?"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:129
+msgid "Show Raw Data"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:91
+msgid "Show Raw Topics"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:58
+msgid "Type"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:19
+msgid "Method Id"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:8
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:31
+msgid "To see decoded input data, the contract must be verified."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:17
+msgid "Transaction Info"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:28
+msgid "Transaction Inputs"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:34
+msgid "Verify the contract "
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:34
+msgid "here"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:65
+msgid "Failed to decode input data."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:53
+msgid "Error rendering value"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:42
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:69
+msgid "Copy Value"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:41
+msgid "Failed to decode log data."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:54
+msgid "Log Data"
+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 b8f82addb3..5e81eec55b 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
@@ -56,7 +56,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:58
+#: lib/block_scout_web/views/transaction_view.ex:64
msgid "(Awaiting internal transactions for status)"
msgstr ""
@@ -151,7 +151,7 @@ msgid "Block %{block_number} - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:59
+#: lib/block_scout_web/templates/transaction/overview.html.eex:60
msgid "Block Confirmations"
msgstr ""
@@ -166,7 +166,7 @@ msgid "Block Mined, awaiting import..."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:45
+#: lib/block_scout_web/templates/transaction/overview.html.eex:46
msgid "Block Number"
msgstr ""
@@ -218,6 +218,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:82
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:84
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:92
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:94
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:133
msgid "Close"
msgstr ""
@@ -283,12 +285,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:131
+#: lib/block_scout_web/views/transaction_view.ex:141
msgid "Contract Call"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:130
+#: lib/block_scout_web/views/transaction_view.ex:140
msgid "Contract Creation"
msgstr ""
@@ -329,13 +331,13 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
-#: lib/block_scout_web/templates/transaction/overview.html.eex:10
+#: lib/block_scout_web/templates/transaction/overview.html.eex:11
msgid "Copy Transaction Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
-#: lib/block_scout_web/templates/transaction/overview.html.eex:10
+#: lib/block_scout_web/templates/transaction/overview.html.eex:11
msgid "Copy Txn Hash"
msgstr ""
@@ -355,7 +357,9 @@ msgid "Curl"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:54
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:33
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:60
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:124
msgid "Data"
msgstr ""
@@ -392,12 +396,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:62
+#: lib/block_scout_web/views/transaction_view.ex:68
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:60
+#: lib/block_scout_web/views/transaction_view.ex:66
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@@ -406,7 +410,7 @@ msgstr ""
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:16
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:19
#: lib/block_scout_web/templates/transaction/_tile.html.eex:26
-#: lib/block_scout_web/templates/transaction/overview.html.eex:182
+#: lib/block_scout_web/templates/transaction/overview.html.eex:110
#: lib/block_scout_web/views/wei_helpers.ex:72
msgid "Ether"
msgstr "POA"
@@ -445,7 +449,7 @@ msgid "GET"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:195
+#: lib/block_scout_web/templates/transaction/overview.html.eex:123
msgid "Gas"
msgstr ""
@@ -489,9 +493,7 @@ msgid "Indexing Tokens"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:81
-#: lib/block_scout_web/templates/transaction/overview.html.eex:88
-#: lib/block_scout_web/templates/transaction/overview.html.eex:95
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:3
msgid "Input"
msgstr ""
@@ -510,7 +512,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:213
-#: lib/block_scout_web/views/transaction_view.ex:180
+#: lib/block_scout_web/views/transaction_view.ex:190
msgid "Internal Transactions"
msgstr ""
@@ -528,7 +530,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:207
+#: lib/block_scout_web/templates/transaction/overview.html.eex:135
msgid "Limit"
msgstr ""
@@ -536,7 +538,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:181
+#: lib/block_scout_web/views/transaction_view.ex:191
msgid "Logs"
msgstr ""
@@ -548,7 +550,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:49
+#: lib/block_scout_web/views/transaction_view.ex:55
msgid "Max of"
msgstr ""
@@ -589,6 +591,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:29
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:31
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:57
msgid "Name"
msgstr ""
@@ -600,7 +604,7 @@ msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:23
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:74
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:151
msgid "Newer"
msgstr ""
@@ -623,7 +627,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:69
-#: lib/block_scout_web/templates/transaction/overview.html.eex:66
+#: lib/block_scout_web/templates/transaction/overview.html.eex:67
msgid "Nonce"
msgstr ""
@@ -682,9 +686,9 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
-#: lib/block_scout_web/templates/transaction/overview.html.eex:54
-#: lib/block_scout_web/views/transaction_view.ex:57
-#: lib/block_scout_web/views/transaction_view.ex:87
+#: lib/block_scout_web/templates/transaction/overview.html.eex:55
+#: lib/block_scout_web/views/transaction_view.ex:63
+#: lib/block_scout_web/views/transaction_view.ex:97
msgid "Pending"
msgstr ""
@@ -789,14 +793,14 @@ msgid "Showing 250 addresses of"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:59
+#: lib/block_scout_web/views/transaction_view.ex:65
msgid "Success"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
-#: lib/block_scout_web/templates/transaction/overview.html.eex:71
+#: lib/block_scout_web/templates/transaction/overview.html.eex:72
msgid "TX Fee"
msgstr ""
@@ -822,7 +826,7 @@ msgid "There are no internal transactions for this transaction."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:68
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:145
msgid "There are no logs for this transaction."
msgstr ""
@@ -862,7 +866,7 @@ msgid "There are no transfers for this Token."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:23
+#: lib/block_scout_web/templates/transaction/overview.html.eex:24
msgid "This transaction is pending confirmation."
msgstr ""
@@ -900,7 +904,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
-#: lib/block_scout_web/views/transaction_view.ex:129
+#: lib/block_scout_web/views/transaction_view.ex:139
msgid "Token Transfer"
msgstr ""
@@ -912,7 +916,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:179
+#: lib/block_scout_web/views/transaction_view.ex:189
msgid "Token Transfers"
msgstr ""
@@ -934,7 +938,7 @@ msgid "Top Accounts - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction_log/index.html.eex:26
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:88
msgid "Topics"
msgstr ""
@@ -954,7 +958,7 @@ msgid "Total transactions"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:132
+#: lib/block_scout_web/views/transaction_view.ex:142
msgid "Transaction"
msgstr ""
@@ -970,7 +974,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/not_found.html.eex:14
-#: lib/block_scout_web/templates/transaction/overview.html.eex:15
+#: lib/block_scout_web/templates/transaction/overview.html.eex:16
msgid "Transaction Details"
msgstr ""
@@ -1023,7 +1027,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:200
+#: lib/block_scout_web/templates/transaction/overview.html.eex:128
msgid "Used"
msgstr ""
@@ -1044,7 +1048,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:182
+#: lib/block_scout_web/templates/transaction/overview.html.eex:110
msgid "Value"
msgstr ""
@@ -1171,7 +1175,7 @@ msgstr ""
msgid "Reward"
msgstr ""
-#, elixir-format, fuzzy
+#, elixir-format
#: lib/block_scout_web/views/internal_transaction_view.ex:26
msgid "Self-Destruct"
msgstr ""
@@ -1228,22 +1232,15 @@ msgid "This API is provided for developers transitioning their applications from
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:153
+#: lib/block_scout_web/templates/transaction/overview.html.eex:80
msgid "Raw Input"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:156
+#: lib/block_scout_web/templates/transaction/overview.html.eex:83
msgid "Show Raw Input"
msgstr ""
-#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:130
-#: lib/block_scout_web/templates/transaction/overview.html.eex:140
-#: lib/block_scout_web/templates/transaction/overview.html.eex:164
-msgid "copy"
-msgstr ""
-
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "Error trying to fetch transactions."
@@ -1323,3 +1320,88 @@ msgstr ""
#: lib/block_scout_web/views/internal_transaction_view.ex:24
msgid "Static Call"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:26
+msgid "Decoded"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:59
+msgid "Indexed?"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:129
+msgid "Show Raw Data"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:91
+msgid "Show Raw Topics"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:58
+msgid "Type"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:19
+msgid "Method Id"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:8
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:31
+msgid "To see decoded input data, the contract must be verified."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:17
+msgid "Transaction Info"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:28
+msgid "Transaction Inputs"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:34
+msgid "Verify the contract "
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:34
+msgid "here"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:65
+msgid "Failed to decode input data."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:53
+msgid "Error rendering value"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:42
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:69
+msgid "Copy Value"
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:41
+msgid "Failed to decode log data."
+msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction_log/index.html.eex:54
+msgid "Log Data"
+msgstr ""
diff --git a/apps/block_scout_web/test/block_scout_web/views/abi_encoded_value_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/abi_encoded_value_view_test.exs
new file mode 100644
index 0000000000..c095bb4de4
--- /dev/null
+++ b/apps/block_scout_web/test/block_scout_web/views/abi_encoded_value_view_test.exs
@@ -0,0 +1,123 @@
+defmodule BlockScoutWeb.ABIEncodedValueViewTest do
+ use BlockScoutWeb.ConnCase, async: true
+
+ alias BlockScoutWeb.ABIEncodedValueView
+
+ defp value_html(type, value) do
+ type
+ |> ABIEncodedValueView.value_html(value)
+ |> case do
+ :error ->
+ raise "failed to generate html"
+
+ other ->
+ other
+ end
+ |> Phoenix.HTML.Safe.to_iodata()
+ |> IO.iodata_to_binary()
+ end
+
+ defp copy_text(type, value) do
+ type
+ |> ABIEncodedValueView.copy_text(value)
+ |> case do
+ :error ->
+ raise "failed to generate copy text"
+
+ other ->
+ other
+ end
+ |> Phoenix.HTML.Safe.to_iodata()
+ |> IO.iodata_to_binary()
+ end
+
+ describe "value_html/2" do
+ test "it formats addresses as links" do
+ address = "0x0000000000000000000000000000000000000000"
+ address_bytes = address |> String.trim_leading("0x") |> Base.decode16!()
+
+ expected = ~s(#{address} )
+
+ assert value_html("address", address_bytes) == expected
+ end
+
+ test "it formats lists with newlines and spaces" do
+ expected =
+ String.trim("""
+ [
+ 1,
+ 2,
+ 3,
+ 4
+ ]
+ """)
+
+ assert value_html("uint[]", [1, 2, 3, 4]) == expected
+ end
+
+ test "it formats nested lists with nested depth" do
+ expected =
+ String.trim("""
+ [
+ [
+ 1,
+ 2
+ ],
+ [
+ 3,
+ 4
+ ]
+ ]
+ """)
+
+ assert value_html("uint[][]", [[1, 2], [3, 4]]) == expected
+ end
+
+ test "it formats lists of addresses as a list of links" do
+ address = "0x0000000000000000000000000000000000000000"
+ address_link = ~s(#{address} )
+
+ expected =
+ String.trim("""
+ [
+ #{address_link},
+ #{address_link},
+ #{address_link},
+ #{address_link}
+ ]
+ """)
+
+ address_bytes = "0x0000000000000000000000000000000000000000" |> String.trim_leading("0x") |> Base.decode16!()
+
+ assert value_html("address[4]", [address_bytes, address_bytes, address_bytes, address_bytes]) == expected
+ end
+
+ test "it renders :dynamic values as bytes" do
+ assert value_html("uint", {:dynamic, <<1>>}) == "0x01"
+ end
+ end
+
+ describe "copy_text/2" do
+ test "it skips link formatting of addresses" do
+ address = "0x0000000000000000000000000000000000000000"
+ address_bytes = address |> String.trim_leading("0x") |> Base.decode16!()
+
+ assert copy_text("address", address_bytes) == address
+ end
+
+ test "it skips the formatting when copying lists" do
+ assert copy_text("uint[4]", [1, 2, 3, 4]) == "[1, 2, 3, 4]"
+ end
+
+ test "it copies bytes as their hex representation" do
+ hex = "0xffffff"
+ bytes = hex |> String.trim_leading("0x") |> Base.decode16!(case: :lower)
+
+ assert copy_text("bytes", bytes) == hex
+ end
+
+ test "it copies :dynamic values as bytes" do
+ assert copy_text("uint", {:dynamic, <<1>>}) == "0x01"
+ end
+ end
+end
diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs
index 16608e0942..02c8ccfe53 100644
--- a/apps/ethereum_jsonrpc/mix.exs
+++ b/apps/ethereum_jsonrpc/mix.exs
@@ -79,7 +79,7 @@ defmodule EthereumJsonrpc.MixProject do
# Convert unix timestamps in JSONRPC to DateTimes
{:timex, "~> 3.4"},
# Encode/decode function names and arguments
- {:ex_abi, "~> 0.1.17"},
+ {:ex_abi, "~> 0.1.18"},
# `:verify_fun` for `Socket.Web.connect`
{:ssl_verify_fun, "~> 1.1"},
# `EthereumJSONRPC.WebSocket`
diff --git a/apps/explorer/lib/explorer/chain/log.ex b/apps/explorer/lib/explorer/chain/log.ex
index 9dcb31405a..b2dc8ca639 100644
--- a/apps/explorer/lib/explorer/chain/log.ex
+++ b/apps/explorer/lib/explorer/chain/log.ex
@@ -3,6 +3,9 @@ defmodule Explorer.Chain.Log do
use Explorer.Schema
+ require Logger
+
+ alias ABI.Event
alias Explorer.Chain.{Address, Data, Hash, Transaction}
@required_attrs ~w(address_hash data index transaction_hash)a
@@ -98,4 +101,64 @@ defmodule Explorer.Chain.Log do
|> cast(attrs, @optional_attrs)
|> validate_required(@required_attrs)
end
+
+ @doc """
+ Decode transaction log data.
+ """
+ def decode(_log, %Transaction{to_address: nil}), do: {:error, :no_to_address}
+
+ def decode(log, transaction = %Transaction{to_address: %{smart_contract: %{abi: abi}}}) when not is_nil(abi) do
+ with {:ok, selector, mapping} <- find_and_decode(abi, log, transaction),
+ identifier <- Base.encode16(selector.method_id, case: :lower),
+ text <- function_call(selector.function, mapping),
+ do: {:ok, identifier, text, mapping}
+ end
+
+ def decode(_log, _transaction), do: {:error, :contract_not_verified}
+
+ defp find_and_decode(abi, log, transaction) do
+ with {selector, mapping} <-
+ abi
+ |> ABI.parse_specification(include_events?: true)
+ |> Event.find_and_decode(
+ decode16!(log.first_topic),
+ decode16!(log.second_topic),
+ decode16!(log.third_topic),
+ decode16!(log.fourth_topic),
+ log.data.bytes
+ ) do
+ {:ok, selector, mapping}
+ end
+ rescue
+ _ ->
+ Logger.warn(fn -> ["Could not decode input data for log from transaction: ", Hash.to_iodata(transaction.hash)] end)
+
+ {:error, :could_not_decode}
+ end
+
+ defp function_call(name, mapping) do
+ text =
+ mapping
+ |> Stream.map(fn {name, type, indexed?, _value} ->
+ indexed_keyword =
+ if indexed? do
+ ["indexed "]
+ else
+ []
+ end
+
+ [type, " ", indexed_keyword, name]
+ end)
+ |> Enum.intersperse(", ")
+
+ IO.iodata_to_binary([name, "(", text, ")"])
+ end
+
+ def decode16!(nil), do: nil
+
+ def decode16!(value) do
+ value
+ |> String.trim_leading("0x")
+ |> Base.decode16!(case: :lower)
+ end
end
diff --git a/apps/explorer/test/explorer/chain/log_test.exs b/apps/explorer/test/explorer/chain/log_test.exs
index 38f264705a..28be44a1af 100644
--- a/apps/explorer/test/explorer/chain/log_test.exs
+++ b/apps/explorer/test/explorer/chain/log_test.exs
@@ -37,4 +37,68 @@ defmodule Explorer.Chain.LogTest do
assert changeset.changes.first_topic === "ham"
end
end
+
+ describe "decode/2" do
+ test "that a contract call transaction that has no verified contract returns a commensurate error" do
+ transaction =
+ :transaction
+ |> insert(to_address: insert(:contract_address))
+ |> Repo.preload(to_address: :smart_contract)
+
+ log = insert(:log, transaction: transaction)
+
+ assert Log.decode(log, transaction) == {:error, :contract_not_verified}
+ end
+
+ test "that a contract call transaction that has a verified contract returns the decoded input data" do
+ smart_contract =
+ insert(:smart_contract,
+ abi: [
+ %{
+ "anonymous" => false,
+ "inputs" => [
+ %{"indexed" => true, "name" => "_from_human", "type" => "string"},
+ %{"indexed" => false, "name" => "_number", "type" => "uint256"},
+ %{"indexed" => true, "name" => "_belly", "type" => "bool"}
+ ],
+ "name" => "WantsPets",
+ "type" => "event"
+ }
+ ]
+ )
+
+ topic1 = "0x" <> Base.encode16(:keccakf1600.hash(:sha3_256, "WantsPets(string,uint256,bool)"), case: :lower)
+ topic2 = "0x" <> Base.encode16(:keccakf1600.hash(:sha3_256, "bob"), case: :lower)
+ topic3 = "0x0000000000000000000000000000000000000000000000000000000000000001"
+ data = "0x0000000000000000000000000000000000000000000000000000000000000000"
+
+ to_address = insert(:address, smart_contract: smart_contract)
+
+ transaction =
+ :transaction_to_verified_contract
+ |> insert(to_address: to_address)
+ |> Repo.preload(to_address: :smart_contract)
+
+ log =
+ insert(:log,
+ transaction: transaction,
+ first_topic: topic1,
+ second_topic: topic2,
+ third_topic: topic3,
+ fourth_topic: nil,
+ data: data
+ )
+
+ assert Log.decode(log, transaction) ==
+ {:ok, "eb9b3c4c", "WantsPets(string indexed _from_human, uint256 _number, bool indexed _belly)",
+ [
+ {"_from_human", "string", true,
+ {:dynamic,
+ <<56, 228, 122, 123, 113, 157, 206, 99, 102, 42, 234, 244, 52, 64, 50, 111, 85, 27, 138, 126, 225,
+ 152, 206, 227, 92, 181, 213, 23, 242, 210, 150, 162>>}},
+ {"_number", "uint256", false, 0},
+ {"_belly", "bool", true, true}
+ ]}
+ end
+ end
end
diff --git a/mix.lock b/mix.lock
index a1d0a1c603..3a6bf7bd26 100644
--- a/mix.lock
+++ b/mix.lock
@@ -28,7 +28,7 @@
"earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.4.2", "332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf", [:mix], [], "hexpm"},
- "ex_abi": {:hex, :ex_abi, "0.1.17", "11822f88b3ed70773c64858a49321b3c51ed913128a3f9fc7a05fa7ceb19d8fa", [:mix], [{:exth_crypto, "~> 0.1.4", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm"},
+ "ex_abi": {:hex, :ex_abi, "0.1.18", "19db9bffdd201edbdff97d7dd5849291218b17beda045c1b76bff5248964f37d", [:mix], [{:exth_crypto, "~> 0.1.4", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"ex_cldr": {:hex, :ex_cldr, "1.3.2", "8f4a00c99d1c537b8e8db7e7903f4bd78d82a7289502d080f70365392b13921b", [:mix], [{:abnf2, "~> 0.1", [hex: :abnf2, optional: false]}, {:decimal, "~> 1.4", [hex: :decimal, optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, optional: true]}, {:poison, "~> 2.1 or ~> 3.0", [hex: :poison, optional: true]}]},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "1.2.0", "ef27299922da913ffad1ed296cacf28b6452fc1243b77301dc17c03276c6ee34", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, optional: false]}, {:ex_cldr, "~> 1.3", [hex: :ex_cldr, optional: false]}, {:poison, "~> 2.1 or ~> 3.1", [hex: :poison, optional: false]}]},
"ex_cldr_units": {:hex, :ex_cldr_units, "1.1.1", "b3c7256709bdeb3740a5f64ce2bce659eb9cf4cc1afb4cf94aba033b4a18bc5f", [:mix], [{:ex_cldr, "~> 1.0", [hex: :ex_cldr, optional: false]}, {:ex_cldr_numbers, "~> 1.0", [hex: :ex_cldr_numbers, optional: false]}]},