Add page to verify contract

pull/182/head
Amanda Sposito 7 years ago
parent 1e449cca99
commit b3d6964650
  1. 3
      apps/explorer/config/config.exs
  2. 46
      apps/explorer/lib/explorer/smart_contract/solidity/compiler_version.ex
  3. 34
      apps/explorer/test/explorer/smart_contract/solidity/compiler_version_test.exs
  4. 5739
      apps/explorer/test/support/fixture/smart_contract/solc_bin.json
  5. 1
      apps/explorer_web/assets/css/app.scss
  6. 14
      apps/explorer_web/assets/css/components/_all.scss
  7. 23
      apps/explorer_web/lib/explorer_web/controllers/address_verify_contract_controller.ex
  8. 7
      apps/explorer_web/lib/explorer_web/router.ex
  9. 47
      apps/explorer_web/lib/explorer_web/templates/address_verify_contract/new.html.eex
  10. 3
      apps/explorer_web/lib/explorer_web/views/address_verify_contract_view.ex
  11. 2
      mix.lock

@ -26,6 +26,9 @@ config :explorer, Explorer.Market.History.Cataloger, enabled: true
config :explorer, Explorer.Repo, migration_timestamps: [type: :utc_datetime]
config :explorer,
solc_bin_api_url: "https://solc-bin.ethereum.org"
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

@ -0,0 +1,46 @@
defmodule Explorer.SmartContract.Solidity.CompilerVersion do
@moduledoc """
Adapter for fetching compiler versions from https://solc-bin.ethereum.org/bin/list.json.
"""
alias HTTPoison.{Error, Response}
@doc """
Fetches list of compilers from Ethereum Solidity API.
"""
def fetch_versions() do
headers = [{"Content-Type", "application/json"}]
case HTTPoison.get(source_url(), headers) do
{:ok, %Response{body: body, status_code: 200}} ->
{:ok, format_data(body)}
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 ->
{:error, decode_json(body)["error"]}
{:error, %Error{reason: reason}} ->
{:error, reason}
end
end
defp format_data(json) do
{:ok, releases} =
Jason.decode!(json)
|> Map.fetch("releases")
Map.to_list(releases)
|> Enum.map(fn {key, _value} -> {key, key} end)
|> Enum.sort()
|> Enum.reverse()
end
defp decode_json(json) do
Jason.decode!(json)
end
defp source_url do
solc_bin_api_url = Application.get_env(:explorer, :solc_bin_api_url)
"#{solc_bin_api_url}/bin/list.json"
end
end

@ -0,0 +1,34 @@
defmodule Explorer.SmartContract.Solidity.CompilerVersionTest do
use ExUnit.Case
doctest Explorer.SmartContract.Solidity.CompilerVersion
alias Explorer.SmartContract.Solidity.CompilerVersion
alias Plug.Conn
describe "fetch_versions" do
setup do
bypass = Bypass.open()
Application.put_env(:explorer, :solc_bin_api_url, "http://localhost:#{bypass.port}")
{:ok, bypass: bypass}
end
test "fetches the list of the solidity compiler versions", %{ bypass: bypass } do
Bypass.expect(bypass, fn conn ->
assert "GET" == conn.method
assert "/bin/list.json" == conn.request_path
Conn.resp(conn, 200, solc_bin_versions())
end)
assert {:ok, versions} = CompilerVersion.fetch_versions()
assert Enum.any?(versions, fn (item) -> item == {"0.4.9", "0.4.9"} end) == true
end
end
def solc_bin_versions() do
File.read!("./test/support/fixture/smart_contract/solc_bin.json")
end
end

@ -38,6 +38,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "node_modules/bootstrap/scss/tables";
@import "node_modules/bootstrap/scss/nav";
@import "node_modules/bootstrap/scss/card";
@import "node_modules/bootstrap/scss/forms";
//Custom theme
@import "theme/theme_ribbon";

@ -0,0 +1,14 @@
@import "section";
@import "dot";
@import "address";
@import "block";
@import "blocks";
@import "chain";
@import "footer";
@import "header";
@import "internal_transaction";
@import "pagination";
@import "transaction";
@import "transaction_log";
@import "transactions";

@ -0,0 +1,23 @@
defmodule ExplorerWeb.AddressVerifyContractController do
use ExplorerWeb, :controller
alias Explorer.Chain
alias Explorer.SmartContract.Solidity.CompilerVersion
def new(conn, %{"address_id" => address_hash_string}) do
{:ok, hash} = Chain.string_to_address_hash(address_hash_string)
{:ok, address} = Chain.hash_to_address(hash)
changeset = Chain.Address.changeset(%Chain.Address{}, %{})
{:ok, compiler_versions} = CompilerVersion.fetch_versions()
render(conn, "new.html",
address: address,
changeset: changeset,
compiler_versions: compiler_versions)
end
def create(_conn, _params) do
end
end

@ -79,6 +79,13 @@ defmodule ExplorerWeb.Router do
AddressContractController,
only: [:index],
as: :contract
end
resources(
"/contract",
AddressVerifyContractController,
only: [:new, :create],
as: :verify_contract
)
end

@ -0,0 +1,47 @@
<section class="container__section block">
<div class="address__container">
<div class="address__tabs">
<h2 class="address__tab address__tab--active">
<%= link(
gettext("Contract Source Code"),
class: "address__link address__link--active",
to: '#'
) %>
</h2>
</div>
<div class="contract__container">
<%= form_for @changeset,
address_verify_contract_path(@conn, :create, @conn.assigns.locale, @conn.params["address_id"]),
fn f -> %>
<div class="form-group">
<label>Contract Address</label>
<%= text_input f, :address, class: "form-control" %>
</div>
<div class="form-group">
<label>Contract Name:</label>
<%= text_input f, :name, class: "form-control" %>
</div>
<div class="form-group">
<label>Compiler:</label>
<%= select f, :compiler, @compiler_versions, class: "form-control" %>
</div>
<div class="form-group">
<label>Optimization:</label>
<%= select f, :optimization, ["yes", "no"], class: "form-control" %>
</div>
<div class="form-group">
<label>Enter the Solidity Contract Code below</label>
<%= textarea f, :code, class: "form-control", rows: 3 %>
</div>
<%= submit "Verify and publish", class: "button--primary" %>
<%= reset "Reset", class: "button--tertiary" %>
<% end %>
</div>
</div>
</section>

@ -0,0 +1,3 @@
defmodule ExplorerWeb.AddressVerifyContractView do
use ExplorerWeb, :view
end

@ -73,5 +73,5 @@
"tzdata": {:hex, :tzdata, "0.5.16", "13424d3afc76c68ff607f2df966c0ab4f3258859bbe3c979c9ed1606135e7352", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},
"uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm"},
"wallaby": {:hex, :wallaby, "0.20.0", "cc6663555ff7b05afbebb2a8b461d18a5b321658b9017f7bc77d494b7063266a", [:mix], [{:httpoison, "~> 0.12", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm"},
"wallaby": {:hex, :wallaby, "0.20.0", "cc6663555ff7b05afbebb2a8b461d18a5b321658b9017f7bc77d494b7063266a", [:mix], [{:httpoison, "~> 0.12", [hex: :httpoison, optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}]},
}

Loading…
Cancel
Save