diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex
index 788d8d4242..e40ccb171e 100644
--- a/apps/explorer/lib/explorer/smart_contract/reader.ex
+++ b/apps/explorer/lib/explorer/smart_contract/reader.ex
@@ -65,25 +65,25 @@ defmodule Explorer.SmartContract.Reader do
$ Explorer.SmartContract.Reader.read_only_functions("0x798465571ae21a184a272f044f991ad1d5f87a3f")
=> [
- %{
- "constant" => true,
- "inputs" => [],
- "name" => "get",
- "outputs" => [%{"name" => "", "type" => "uint256", "value" => 0}],
- "payable" => false,
- "stateMutability" => "view",
- "type" => "function"
- },
- %{
- "constant" => true,
- "inputs" => [%{"name" => "x", "type" => "uint256"}],
- "name" => "with_arguments",
- "outputs" => [%{"name" => "", "type" => "bool", "value" => ""}],
- "payable" => false,
- "stateMutability" => "view",
- "type" => "function"
- }
- ]
+ %{
+ "constant" => true,
+ "inputs" => [],
+ "name" => "get",
+ "outputs" => [%{"name" => "", "type" => "uint256", "value" => 0}],
+ "payable" => false,
+ "stateMutability" => "view",
+ "type" => "function"
+ },
+ %{
+ "constant" => true,
+ "inputs" => [%{"name" => "x", "type" => "uint256"}],
+ "name" => "with_arguments",
+ "outputs" => [%{"name" => "", "type" => "bool", "value" => ""}],
+ "payable" => false,
+ "stateMutability" => "view",
+ "type" => "function"
+ }
+ ]
"""
@spec read_only_functions(%Explorer.Chain.Hash{}) :: [%{}]
def read_only_functions(contract_address_hash) do
@@ -140,7 +140,7 @@ defmodule Explorer.SmartContract.Reader do
defp fetch_from_blockchain(contract_address_hash, %{name: name, args: args, outputs: outputs}) do
contract_address_hash
- |> query_contract(%{name => args})
+ |> query_contract(%{name => normalize_args(args)})
|> link_outputs_and_values(outputs, name)
end
diff --git a/apps/explorer_web/assets/css/app.scss b/apps/explorer_web/assets/css/app.scss
index 668ff54d93..f7d4af038c 100644
--- a/apps/explorer_web/assets/css/app.scss
+++ b/apps/explorer_web/assets/css/app.scss
@@ -32,6 +32,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "node_modules/bootstrap/scss/utilities/text";
@import "node_modules/bootstrap/scss/utilities/background";
@import "node_modules/bootstrap/scss/utilities/position";
+@import "node_modules/bootstrap/scss/utilities/borders";
// Bootstrap Components
@import "node_modules/bootstrap/scss/dropdown";
diff --git a/apps/explorer_web/assets/js/app.js b/apps/explorer_web/assets/js/app.js
index 5b071039f0..f14cd6d42d 100644
--- a/apps/explorer_web/assets/js/app.js
+++ b/apps/explorer_web/assets/js/app.js
@@ -23,6 +23,7 @@ import './lib/from_now'
import './lib/market_history_chart'
import './lib/reload_button'
import './lib/tooltip'
+import './lib/smart_contract/read_function'
import './pages/address'
import './pages/transaction'
diff --git a/apps/explorer_web/assets/js/lib/smart_contract/read_function.js b/apps/explorer_web/assets/js/lib/smart_contract/read_function.js
new file mode 100644
index 0000000000..a80e05cae9
--- /dev/null
+++ b/apps/explorer_web/assets/js/lib/smart_contract/read_function.js
@@ -0,0 +1,31 @@
+import $ from 'jquery'
+
+const readFunction = (element) => {
+ const $element = $(element)
+ const $form = $element.find('[data-function-form]')
+
+ const $responseContainer = $element.find('[data-function-response]')
+
+ $form.on('submit', (event) => {
+ event.preventDefault()
+
+ const url = $form.data('url')
+ const $functionName = $form.find('input[name=function_name]')
+ const $functionInputs = $form.find('input[name=function_input]')
+
+ const args = $.map($functionInputs, element => {
+ return $(element).val()
+ })
+
+ const data = {
+ function_name: $functionName.val(),
+ args
+ }
+
+ $.get(url, data, response => $responseContainer.html(response))
+ })
+}
+
+$('[data-function]').each((_, element) => {
+ readFunction(element)
+})
diff --git a/apps/explorer_web/assets/package-lock.json b/apps/explorer_web/assets/package-lock.json
index e19242620b..5140c4142e 100644
--- a/apps/explorer_web/assets/package-lock.json
+++ b/apps/explorer_web/assets/package-lock.json
@@ -11468,7 +11468,7 @@
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
diff --git a/apps/explorer_web/config/test.exs b/apps/explorer_web/config/test.exs
index dc2523f19b..1eadb09989 100644
--- a/apps/explorer_web/config/test.exs
+++ b/apps/explorer_web/config/test.exs
@@ -10,4 +10,4 @@ config :explorer_web, ExplorerWeb.Endpoint,
server: true
# Configure wallaby
-config :wallaby, screenshot_on_failure: true
+config :wallaby, screenshot_on_failure: true, js_errors: false
diff --git a/apps/explorer_web/lib/explorer_web/controllers/address_read_contract_controller.ex b/apps/explorer_web/lib/explorer_web/controllers/address_read_contract_controller.ex
new file mode 100644
index 0000000000..2879e9eca0
--- /dev/null
+++ b/apps/explorer_web/lib/explorer_web/controllers/address_read_contract_controller.ex
@@ -0,0 +1,60 @@
+defmodule ExplorerWeb.AddressReadContractController do
+ use ExplorerWeb, :controller
+
+ alias Explorer.{Chain, Market}
+ alias Explorer.ExchangeRates.Token
+ alias Explorer.SmartContract.Reader
+
+ import ExplorerWeb.AddressController, only: [transaction_count: 1]
+
+ def index(conn, %{"address_id" => address_hash_string}) do
+ with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
+ {:ok, address} <- Chain.find_contract_address(address_hash) do
+ read_only_functions = Reader.read_only_functions(address_hash)
+
+ render(
+ conn,
+ "index.html",
+ read_only_functions: read_only_functions,
+ address: address,
+ exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
+ transaction_count: transaction_count(address)
+ )
+ else
+ :error ->
+ not_found(conn)
+
+ {:error, :not_found} ->
+ not_found(conn)
+ end
+ end
+
+ def show(conn, params) do
+ with true <- ajax?(conn),
+ {:ok, address_hash} <- Chain.string_to_address_hash(params["address_id"]),
+ outputs =
+ Reader.query_function(
+ address_hash,
+ %{name: params["function_name"], args: params["args"]}
+ ) do
+ conn
+ |> put_status(200)
+ |> put_layout(false)
+ |> render(
+ "_function_response.html",
+ function_name: params["function_name"],
+ outputs: outputs
+ )
+ else
+ _ ->
+ not_found(conn)
+ end
+ end
+
+ defp ajax?(conn) do
+ case get_req_header(conn, "x-requested-with") do
+ [value] -> value in ["XMLHttpRequest", "xmlhttprequest"]
+ [] -> false
+ end
+ end
+end
diff --git a/apps/explorer_web/lib/explorer_web/router.ex b/apps/explorer_web/lib/explorer_web/router.ex
index e253e822e3..a2ac976daf 100644
--- a/apps/explorer_web/lib/explorer_web/router.ex
+++ b/apps/explorer_web/lib/explorer_web/router.ex
@@ -85,6 +85,13 @@ defmodule ExplorerWeb.Router do
only: [:new, :create],
as: :verify_contract
)
+
+ resources(
+ "/read_contract",
+ AddressReadContractController,
+ only: [:index, :show],
+ as: :read_contract
+ )
end
get("/search", ChainController, :search)
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_contract/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_contract/index.html.eex
index aeba2becf1..a0683e197c 100644
--- a/apps/explorer_web/lib/explorer_web/templates/address_contract/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/address_contract/index.html.eex
@@ -31,6 +31,14 @@
<% end %>
<% end %>
+ <%= if smart_contract_with_read_only_functions?(@address) do %>
+
+ <%= link(
+ gettext("Read Contract"),
+ to: address_read_contract_path(@conn, :index, @conn.assigns.locale, @conn.params["address_id"]),
+ class: "nav-link")%>
+
+ <% end %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_internal_transaction/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_internal_transaction/index.html.eex
index 9b62af2122..ac59c248ac 100644
--- a/apps/explorer_web/lib/explorer_web/templates/address_internal_transaction/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/address_internal_transaction/index.html.eex
@@ -36,6 +36,14 @@
<% end %>
<% end %>
+ <%= if smart_contract_with_read_only_functions?(@address) do %>
+
+ <%= link(
+ gettext("Read Contract"),
+ to: address_read_contract_path(@conn, :index, @conn.assigns.locale, @conn.params["address_id"]),
+ class: "nav-link")%>
+
+ <% end %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_read_contract/_function_response.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_read_contract/_function_response.html.eex
new file mode 100644
index 0000000000..11dcd737ea
--- /dev/null
+++ b/apps/explorer_web/lib/explorer_web/templates/address_read_contract/_function_response.html.eex
@@ -0,0 +1,7 @@
+
+ [ <%= @function_name %> method Response ]
+
+ <%= for item <- @outputs do %>
+ <%= item["type"] %> : <%= item["value"] %>
+ <% end %>
+
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_read_contract/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_read_contract/index.html.eex
new file mode 100644
index 0000000000..2ed7869aa8
--- /dev/null
+++ b/apps/explorer_web/lib/explorer_web/templates/address_read_contract/index.html.eex
@@ -0,0 +1,99 @@
+
+
+ <%= render ExplorerWeb.AddressView, "overview.html", assigns %>
+
+
+
+
+
+
+
+ <%= gettext("Read Contract Information") %>
+
+
+ <%= for {function, counter} <- Enum.with_index(@read_only_functions, 1) do %>
+
+
+ <%= counter %>.
+
+ <%= function["name"] %>
+
+ →
+
+
+ <%= if queryable?(function["inputs"]) do %>
+
+ <% else %>
+
+ <%= for output <- function["outputs"] do %>
+ <%= if address?(output["type"]) do %>
+ <%= link(
+ output["value"],
+ to: address_path(@conn, :show, @conn.assigns.locale, output["value"])
+ ) %>
+ <% else %>
+ <%= output["value"] %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+
+
+ <%= if (queryable?(function["inputs"])), do: raw "↳" %>
+
+ <%= for output <- function["outputs"] do %>
+ <%= output["type"] %>
+ <% end %>
+
+
+
+
+ <% end %>
+
+
+
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
index 146de72031..4045199c3b 100644
--- a/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
@@ -36,6 +36,14 @@
<% end %>
<% end %>
+ <%= if smart_contract_with_read_only_functions?(@address) do %>
+
+ <%= link(
+ gettext("Read Contract"),
+ to: address_read_contract_path(@conn, :index, @conn.assigns.locale, @conn.params["address_id"]),
+ class: "nav-link")%>
+
+ <% end %>
diff --git a/apps/explorer_web/lib/explorer_web/views/address_contract_view.ex b/apps/explorer_web/lib/explorer_web/views/address_contract_view.ex
index 8fc6049072..47db821975 100644
--- a/apps/explorer_web/lib/explorer_web/views/address_contract_view.ex
+++ b/apps/explorer_web/lib/explorer_web/views/address_contract_view.ex
@@ -1,7 +1,7 @@
defmodule ExplorerWeb.AddressContractView do
use ExplorerWeb, :view
- import ExplorerWeb.AddressView, only: [smart_contract_verified?: 1]
+ import ExplorerWeb.AddressView, only: [smart_contract_verified?: 1, smart_contract_with_read_only_functions?: 1]
def format_smart_contract_abi(abi), do: Poison.encode!(abi, pretty: true)
diff --git a/apps/explorer_web/lib/explorer_web/views/address_internal_transaction_view.ex b/apps/explorer_web/lib/explorer_web/views/address_internal_transaction_view.ex
index ddcd7f9ea4..567e261085 100644
--- a/apps/explorer_web/lib/explorer_web/views/address_internal_transaction_view.ex
+++ b/apps/explorer_web/lib/explorer_web/views/address_internal_transaction_view.ex
@@ -1,7 +1,8 @@
defmodule ExplorerWeb.AddressInternalTransactionView do
use ExplorerWeb, :view
- import ExplorerWeb.AddressView, only: [contract?: 1, smart_contract_verified?: 1]
+ import ExplorerWeb.AddressView,
+ only: [contract?: 1, smart_contract_verified?: 1, smart_contract_with_read_only_functions?: 1]
def format_current_filter(filter) do
case filter do
diff --git a/apps/explorer_web/lib/explorer_web/views/address_read_contract_view.ex b/apps/explorer_web/lib/explorer_web/views/address_read_contract_view.ex
new file mode 100644
index 0000000000..bbdf9f0a72
--- /dev/null
+++ b/apps/explorer_web/lib/explorer_web/views/address_read_contract_view.ex
@@ -0,0 +1,9 @@
+defmodule ExplorerWeb.AddressReadContractView do
+ use ExplorerWeb, :view
+
+ import ExplorerWeb.AddressView, only: [smart_contract_verified?: 1]
+
+ def queryable?(inputs), do: Enum.any?(inputs)
+
+ def address?(type), do: type == "address"
+end
diff --git a/apps/explorer_web/lib/explorer_web/views/address_transaction_view.ex b/apps/explorer_web/lib/explorer_web/views/address_transaction_view.ex
index 9436597f8f..89531c532d 100644
--- a/apps/explorer_web/lib/explorer_web/views/address_transaction_view.ex
+++ b/apps/explorer_web/lib/explorer_web/views/address_transaction_view.ex
@@ -1,7 +1,8 @@
defmodule ExplorerWeb.AddressTransactionView do
use ExplorerWeb, :view
- import ExplorerWeb.AddressView, only: [contract?: 1, smart_contract_verified?: 1]
+ import ExplorerWeb.AddressView,
+ only: [contract?: 1, smart_contract_verified?: 1, smart_contract_with_read_only_functions?: 1]
def format_current_filter(filter) do
case filter do
diff --git a/apps/explorer_web/lib/explorer_web/views/address_view.ex b/apps/explorer_web/lib/explorer_web/views/address_view.ex
index cde119d3b7..0819e057fb 100644
--- a/apps/explorer_web/lib/explorer_web/views/address_view.ex
+++ b/apps/explorer_web/lib/explorer_web/views/address_view.ex
@@ -72,4 +72,10 @@ defmodule ExplorerWeb.AddressView do
end
def trimmed_hash(_), do: ""
+
+ def smart_contract_with_read_only_functions?(%Address{smart_contract: %SmartContract{}} = address) do
+ Enum.any?(address.smart_contract.abi, & &1["constant"])
+ end
+
+ def smart_contract_with_read_only_functions?(%Address{smart_contract: nil}), do: false
end
diff --git a/apps/explorer_web/package-lock.json b/apps/explorer_web/package-lock.json
new file mode 100644
index 0000000000..48e341a095
--- /dev/null
+++ b/apps/explorer_web/package-lock.json
@@ -0,0 +1,3 @@
+{
+ "lockfileVersion": 1
+}
diff --git a/apps/explorer_web/priv/gettext/default.pot b/apps/explorer_web/priv/gettext/default.pot
index 69b77e6679..1fcd3a2dfb 100644
--- a/apps/explorer_web/priv/gettext/default.pot
+++ b/apps/explorer_web/priv/gettext/default.pot
@@ -40,10 +40,11 @@ msgstr ""
#: lib/explorer_web/templates/address/overview.html.eex:21
#: lib/explorer_web/templates/address_contract/index.html.eex:10
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:13
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:47
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:55
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:10
#: lib/explorer_web/templates/address_transaction/index.html.eex:13
-#: lib/explorer_web/templates/address_transaction/index.html.eex:47
-#: lib/explorer_web/templates/address_transaction/index.html.eex:123
+#: lib/explorer_web/templates/address_transaction/index.html.eex:55
+#: lib/explorer_web/templates/address_transaction/index.html.eex:131
#: lib/explorer_web/templates/block/index.html.eex:19
#: lib/explorer_web/templates/block_transaction/index.html.eex:124
#: lib/explorer_web/templates/chain/_transactions.html.eex:4
@@ -142,13 +143,13 @@ msgstr ""
msgid "Address"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:98
-#: lib/explorer_web/templates/address_transaction/index.html.eex:109
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:106
+#: lib/explorer_web/templates/address_transaction/index.html.eex:117
#: lib/explorer_web/templates/block_transaction/index.html.eex:142
#: lib/explorer_web/templates/transaction/overview.html.eex:79
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
-#: lib/explorer_web/views/address_internal_transaction_view.ex:9
-#: lib/explorer_web/views/address_transaction_view.ex:9
+#: lib/explorer_web/views/address_internal_transaction_view.ex:10
+#: lib/explorer_web/views/address_transaction_view.ex:10
msgid "From"
msgstr ""
@@ -161,13 +162,13 @@ msgstr ""
msgid "Success"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:86
-#: lib/explorer_web/templates/address_transaction/index.html.eex:97
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:94
+#: lib/explorer_web/templates/address_transaction/index.html.eex:105
#: lib/explorer_web/templates/block_transaction/index.html.eex:144
#: lib/explorer_web/templates/transaction/overview.html.eex:91
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:32
-#: lib/explorer_web/views/address_internal_transaction_view.ex:8
-#: lib/explorer_web/views/address_transaction_view.ex:8
+#: lib/explorer_web/views/address_internal_transaction_view.ex:9
+#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "To"
msgstr ""
@@ -312,10 +313,11 @@ msgstr ""
#: lib/explorer_web/templates/address_contract/index.html.eex:17
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:20
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:52
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:111
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:60
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:119
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:17
#: lib/explorer_web/templates/address_transaction/index.html.eex:20
-#: lib/explorer_web/templates/address_transaction/index.html.eex:52
+#: lib/explorer_web/templates/address_transaction/index.html.eex:60
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:11
#: lib/explorer_web/templates/transaction_log/index.html.eex:11
msgid "Internal Transactions"
@@ -353,10 +355,10 @@ msgstr ""
msgid "Wei"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:80
-#: lib/explorer_web/templates/address_transaction/index.html.eex:91
-#: lib/explorer_web/views/address_internal_transaction_view.ex:10
-#: lib/explorer_web/views/address_transaction_view.ex:10
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:88
+#: lib/explorer_web/templates/address_transaction/index.html.eex:99
+#: lib/explorer_web/views/address_internal_transaction_view.ex:11
+#: lib/explorer_web/views/address_transaction_view.ex:11
msgid "All"
msgstr ""
@@ -473,8 +475,8 @@ msgstr ""
msgid "There are no Transactions"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:125
-#: lib/explorer_web/templates/address_transaction/index.html.eex:138
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:133
+#: lib/explorer_web/templates/address_transaction/index.html.eex:146
#: lib/explorer_web/templates/block/index.html.eex:60
#: lib/explorer_web/templates/block_transaction/index.html.eex:198
#: lib/explorer_web/templates/pending_transaction/index.html.eex:54
@@ -486,15 +488,16 @@ msgstr ""
msgid "Contract Source Code"
msgstr ""
-#: lib/explorer_web/templates/address_contract/index.html.eex:44
+#: lib/explorer_web/templates/address_contract/index.html.eex:52
msgid "Verify and Publish"
msgstr ""
#: lib/explorer_web/templates/address_contract/index.html.eex:27
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:31
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:61
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:69
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:27
#: lib/explorer_web/templates/address_transaction/index.html.eex:31
-#: lib/explorer_web/templates/address_transaction/index.html.eex:61
+#: lib/explorer_web/templates/address_transaction/index.html.eex:69
msgid "Code"
msgstr ""
@@ -589,7 +592,7 @@ msgid "block confirmations"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:81
+#: lib/explorer_web/templates/address_transaction/index.html.eex:89
msgid "Connection Lost, click to load newer transactions"
msgstr ""
@@ -605,7 +608,7 @@ msgid "Internal Transaction"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:76
+#: lib/explorer_web/templates/address_transaction/index.html.eex:84
msgid "More messages have come in"
msgstr ""
@@ -615,12 +618,12 @@ msgid "QR Code"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:118
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:126
msgid "There are no internal transactions for this address."
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:131
+#: lib/explorer_web/templates/address_transaction/index.html.eex:139
msgid "There are no transactions for this address."
msgstr ""
@@ -664,3 +667,21 @@ msgstr ""
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:29
msgid "OUT"
msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:69
+msgid "Query"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_contract/index.html.eex:37
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:42
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:36
+#: lib/explorer_web/templates/address_transaction/index.html.eex:42
+msgid "Read Contract"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:46
+msgid "Read Contract Information"
+msgstr ""
diff --git a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
index a5f8d932e7..b4436e34df 100644
--- a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -52,10 +52,11 @@ msgstr "POA Network Explorer"
#: lib/explorer_web/templates/address/overview.html.eex:21
#: lib/explorer_web/templates/address_contract/index.html.eex:10
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:13
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:47
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:55
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:10
#: lib/explorer_web/templates/address_transaction/index.html.eex:13
-#: lib/explorer_web/templates/address_transaction/index.html.eex:47
-#: lib/explorer_web/templates/address_transaction/index.html.eex:123
+#: lib/explorer_web/templates/address_transaction/index.html.eex:55
+#: lib/explorer_web/templates/address_transaction/index.html.eex:131
#: lib/explorer_web/templates/block/index.html.eex:19
#: lib/explorer_web/templates/block_transaction/index.html.eex:124
#: lib/explorer_web/templates/chain/_transactions.html.eex:4
@@ -154,13 +155,13 @@ msgstr "%{count} transactions in this block"
msgid "Address"
msgstr "Address"
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:98
-#: lib/explorer_web/templates/address_transaction/index.html.eex:109
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:106
+#: lib/explorer_web/templates/address_transaction/index.html.eex:117
#: lib/explorer_web/templates/block_transaction/index.html.eex:142
#: lib/explorer_web/templates/transaction/overview.html.eex:79
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:31
-#: lib/explorer_web/views/address_internal_transaction_view.ex:9
-#: lib/explorer_web/views/address_transaction_view.ex:9
+#: lib/explorer_web/views/address_internal_transaction_view.ex:10
+#: lib/explorer_web/views/address_transaction_view.ex:10
msgid "From"
msgstr "From"
@@ -173,13 +174,13 @@ msgstr "Overview"
msgid "Success"
msgstr "Success"
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:86
-#: lib/explorer_web/templates/address_transaction/index.html.eex:97
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:94
+#: lib/explorer_web/templates/address_transaction/index.html.eex:105
#: lib/explorer_web/templates/block_transaction/index.html.eex:144
#: lib/explorer_web/templates/transaction/overview.html.eex:91
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:32
-#: lib/explorer_web/views/address_internal_transaction_view.ex:8
-#: lib/explorer_web/views/address_transaction_view.ex:8
+#: lib/explorer_web/views/address_internal_transaction_view.ex:9
+#: lib/explorer_web/views/address_transaction_view.ex:9
msgid "To"
msgstr "To"
@@ -324,10 +325,11 @@ msgstr ""
#: lib/explorer_web/templates/address_contract/index.html.eex:17
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:20
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:52
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:111
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:60
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:119
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:17
#: lib/explorer_web/templates/address_transaction/index.html.eex:20
-#: lib/explorer_web/templates/address_transaction/index.html.eex:52
+#: lib/explorer_web/templates/address_transaction/index.html.eex:60
#: lib/explorer_web/templates/transaction_internal_transaction/index.html.eex:11
#: lib/explorer_web/templates/transaction_log/index.html.eex:11
msgid "Internal Transactions"
@@ -365,10 +367,10 @@ msgstr ""
msgid "Wei"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:80
-#: lib/explorer_web/templates/address_transaction/index.html.eex:91
-#: lib/explorer_web/views/address_internal_transaction_view.ex:10
-#: lib/explorer_web/views/address_transaction_view.ex:10
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:88
+#: lib/explorer_web/templates/address_transaction/index.html.eex:99
+#: lib/explorer_web/views/address_internal_transaction_view.ex:11
+#: lib/explorer_web/views/address_transaction_view.ex:11
msgid "All"
msgstr ""
@@ -485,8 +487,8 @@ msgstr ""
msgid "There are no Transactions"
msgstr ""
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:125
-#: lib/explorer_web/templates/address_transaction/index.html.eex:138
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:133
+#: lib/explorer_web/templates/address_transaction/index.html.eex:146
#: lib/explorer_web/templates/block/index.html.eex:60
#: lib/explorer_web/templates/block_transaction/index.html.eex:198
#: lib/explorer_web/templates/pending_transaction/index.html.eex:54
@@ -498,15 +500,16 @@ msgstr ""
msgid "Contract Source Code"
msgstr "Contract Source Code"
-#: lib/explorer_web/templates/address_contract/index.html.eex:44
+#: lib/explorer_web/templates/address_contract/index.html.eex:52
msgid "Verify and Publish"
msgstr ""
#: lib/explorer_web/templates/address_contract/index.html.eex:27
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:31
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:61
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:69
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:27
#: lib/explorer_web/templates/address_transaction/index.html.eex:31
-#: lib/explorer_web/templates/address_transaction/index.html.eex:61
+#: lib/explorer_web/templates/address_transaction/index.html.eex:69
msgid "Code"
msgstr ""
@@ -601,7 +604,7 @@ msgid "block confirmations"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:81
+#: lib/explorer_web/templates/address_transaction/index.html.eex:89
msgid "Connection Lost, click to load newer transactions"
msgstr ""
@@ -617,7 +620,7 @@ msgid "Internal Transaction"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:76
+#: lib/explorer_web/templates/address_transaction/index.html.eex:84
msgid "More messages have come in"
msgstr ""
@@ -627,12 +630,12 @@ msgid "QR Code"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:118
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:126
msgid "There are no internal transactions for this address."
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:131
+#: lib/explorer_web/templates/address_transaction/index.html.eex:139
msgid "There are no transactions for this address."
msgstr ""
@@ -656,7 +659,7 @@ msgstr ""
msgid "at"
msgstr ""
-#, elixir-format, fuzzy
+#, elixir-format
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:36
#: lib/explorer_web/templates/chain/_transactions.html.eex:25
#: lib/explorer_web/templates/transaction/index.html.eex:47
@@ -676,3 +679,21 @@ msgstr ""
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:29
msgid "OUT"
msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:69
+msgid "Query"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_contract/index.html.eex:37
+#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:42
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:36
+#: lib/explorer_web/templates/address_transaction/index.html.eex:42
+msgid "Read Contract"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_read_contract/index.html.eex:46
+msgid "Read Contract Information"
+msgstr ""
diff --git a/apps/explorer_web/test/explorer_web/controllers/address_read_contract_controller_test.exs b/apps/explorer_web/test/explorer_web/controllers/address_read_contract_controller_test.exs
new file mode 100644
index 0000000000..885c810ac7
--- /dev/null
+++ b/apps/explorer_web/test/explorer_web/controllers/address_read_contract_controller_test.exs
@@ -0,0 +1,24 @@
+defmodule ExplorerWeb.AddressReadContractControllerTest do
+ use ExplorerWeb.ConnCase
+
+ describe "GET show/3" do
+ test "only responds to ajax requests", %{conn: conn} do
+ smart_contract = insert(:smart_contract)
+
+ path =
+ address_read_contract_path(
+ ExplorerWeb.Endpoint,
+ :show,
+ :en,
+ smart_contract.address_hash,
+ smart_contract.address_hash,
+ function_name: "get",
+ args: []
+ )
+
+ conn = get(conn, path)
+
+ assert conn.status == 404
+ end
+ end
+end
diff --git a/apps/explorer_web/test/explorer_web/views/address_read_contract_view_test.exs b/apps/explorer_web/test/explorer_web/views/address_read_contract_view_test.exs
new file mode 100644
index 0000000000..ef68d5833b
--- /dev/null
+++ b/apps/explorer_web/test/explorer_web/views/address_read_contract_view_test.exs
@@ -0,0 +1,19 @@
+defmodule ExplorerWeb.AddressReadContractViewTest do
+ use ExplorerWeb.ConnCase, async: true
+
+ alias ExplorerWeb.AddressReadContractView
+
+ describe "queryable?/1" do
+ test "returns true if list of inputs is not empty" do
+ assert AddressReadContractView.queryable?([%{"name" => "argument_name", "type" => "uint256"}]) == true
+ assert AddressReadContractView.queryable?([]) == false
+ end
+ end
+
+ describe "address?/1" do
+ test "returns true if type equals `address`" do
+ assert AddressReadContractView.address?("address") == true
+ assert AddressReadContractView.address?("uint256") == false
+ end
+ end
+end
diff --git a/apps/explorer_web/test/explorer_web/views/address_view_test.exs b/apps/explorer_web/test/explorer_web/views/address_view_test.exs
index a196c5e875..47c3c5f13a 100644
--- a/apps/explorer_web/test/explorer_web/views/address_view_test.exs
+++ b/apps/explorer_web/test/explorer_web/views/address_view_test.exs
@@ -44,4 +44,71 @@ defmodule ExplorerWeb.AddressViewTest do
assert {:ok, _} = Base.decode64(AddressView.qr_code(address))
end
end
+
+ describe "smart_contract_verified?/1" do
+ test "returns true when smart contract is verified" do
+ smart_contract = insert(:smart_contract)
+ address = insert(:address, smart_contract: smart_contract)
+
+ assert AddressView.smart_contract_verified?(address)
+ end
+
+ test "returns false when smart contract is not verified" do
+ address = insert(:address, smart_contract: nil)
+
+ refute AddressView.smart_contract_verified?(address)
+ end
+ end
+
+ describe "smart_contract_with_read_only_functions?/1" do
+ test "returns true when abi has read only functions" do
+ smart_contract =
+ insert(
+ :smart_contract,
+ abi: [
+ %{
+ "constant" => true,
+ "inputs" => [],
+ "name" => "get",
+ "outputs" => [%{"name" => "", "type" => "uint256"}],
+ "payable" => false,
+ "stateMutability" => "view",
+ "type" => "function"
+ }
+ ]
+ )
+
+ address = insert(:address, smart_contract: smart_contract)
+
+ assert AddressView.smart_contract_with_read_only_functions?(address)
+ end
+
+ test "returns false when there is no read only functions" do
+ smart_contract =
+ insert(
+ :smart_contract,
+ abi: [
+ %{
+ "constant" => false,
+ "inputs" => [%{"name" => "x", "type" => "uint256"}],
+ "name" => "set",
+ "outputs" => [],
+ "payable" => false,
+ "stateMutability" => "nonpayable",
+ "type" => "function"
+ }
+ ]
+ )
+
+ address = insert(:address, smart_contract: smart_contract)
+
+ refute AddressView.smart_contract_with_read_only_functions?(address)
+ end
+
+ test "returns false when smart contract is not verified" do
+ address = insert(:address, smart_contract: nil)
+
+ refute AddressView.smart_contract_with_read_only_functions?(address)
+ end
+ end
end