Merge pull request #288 from poanetwork/iff-verify-all-solidity-versions

Give support for all solidity's versions in the contract verification
pull/347/head
Igor Florian 7 years ago committed by GitHub
commit 46271078e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      .circleci/config.yml
  2. 1
      .gitignore
  3. 5
      README.md
  4. 4
      apps/explorer/lib/explorer/smart_contract/publisher.ex
  5. 180
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  6. 30
      apps/explorer/lib/explorer/smart_contract/solidity/compiler_version.ex
  7. 57
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  8. 18
      apps/explorer/package.json
  9. 15
      apps/explorer/priv/compile_solc.js
  10. 3
      apps/explorer/priv/solc.bash
  11. 42
      apps/explorer/test/explorer/smart_contract/publisher_test.exs
  12. 141
      apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
  13. 14
      apps/explorer/test/explorer/smart_contract/solidity/compiler_version_test.exs
  14. 85
      apps/explorer/test/explorer/smart_contract/verifier_test.exs
  15. 32
      apps/explorer/test/support/factory.ex
  16. 296
      apps/explorer/test/support/fixture/smart_contract/solc_bin.json
  17. 6
      apps/explorer_web/lib/explorer_web/templates/address_contract_verification/new.html.eex
  18. 47
      apps/explorer_web/test/explorer_web/features/address_contract_verification_test.exs
  19. 296
      apps/explorer_web/test/support/fixture/smart_contract/solc_bin.json

@ -40,6 +40,20 @@ jobs:
- v6-npm-install-{{ .Branch }} - v6-npm-install-{{ .Branch }}
- v6-npm-install - v6-npm-install
- run:
command: npm install
working_directory: "apps/explorer"
- save_cache:
key: v3-npm-install-{{ .Branch }}-{{ checksum "apps/explorer/package-lock.json" }}
paths: "apps/explorer/node_modules"
- save_cache:
key: v3-npm-install-{{ .Branch }}
paths: "apps/explorer/node_modules"
- save_cache:
key: v3-npm-install
paths: "apps/explorer/node_modules"
- run: - run:
command: npm install command: npm install
working_directory: "apps/explorer_web/assets" working_directory: "apps/explorer_web/assets"
@ -101,7 +115,6 @@ jobs:
- mix.exs - mix.exs
- mix.lock - mix.lock
- appspec.yml - appspec.yml
check_formatted: check_formatted:
docker: docker:
# Ensure .tool-versions matches # Ensure .tool-versions matches
@ -300,14 +313,6 @@ jobs:
name: Wait for DB name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Install 'solc'
command: |
echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu trusty main' | sudo tee /etc/apt/sources.list.d/pgdg.list > /dev/null
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 923F6CA9
sudo apt-get update
sudo apt-get install solc
- run: mix coveralls.circle --umbrella - run: mix coveralls.circle --umbrella
- store_test_results: - store_test_results:

1
.gitignore vendored

@ -15,6 +15,7 @@ npm-debug.log
# Static artifacts # Static artifacts
/apps/explorer_web/assets/node_modules /apps/explorer_web/assets/node_modules
/apps/explorer/node_modules
# Since we are building assets from assets/, # Since we are building assets from assets/,
# we ignore priv/static. You may want to comment # we ignore priv/static. You may want to comment

@ -26,7 +26,9 @@ To get POA Explorer up and running locally:
* Set up some default configuration with: `cp apps/explorer_web/config/dev.secret.exs.example apps/explorer_web/config/dev.secret.exs` * Set up some default configuration with: `cp apps/explorer_web/config/dev.secret.exs.example apps/explorer_web/config/dev.secret.exs`
* Install dependencies with `mix do deps.get, local.rebar, deps.compile, compile` * Install dependencies with `mix do deps.get, local.rebar, deps.compile, compile`
* Create and migrate your database with `mix ecto.create && mix ecto.migrate` * Create and migrate your database with `mix ecto.create && mix ecto.migrate`
* Install Node.js dependencies with `cd apps/explorer_web/assets && npm install; cd -` * Install Node.js dependencies with:
* `cd apps/explorer_web/assets && npm install; cd -`
* `cd apps/explorer && npm install; cd -`
* Start Phoenix with `mix phx.server` * Start Phoenix with `mix phx.server`
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
@ -60,7 +62,6 @@ Configure your local CCMenu with the following url: [`https://circleci.com/gh/po
#### Prerequisites #### Prerequisites
* PhantomJS (for wallaby) * PhantomJS (for wallaby)
* `Solidity` - http://solidity.readthedocs.io/en/v0.4.24/installing-solidity.html
#### Running the tests #### Running the tests

@ -14,7 +14,7 @@ defmodule Explorer.SmartContract.Publisher do
Explorer.SmartContract.Publisher.publish( Explorer.SmartContract.Publisher.publish(
"0x0f95fa9bc0383e699325f2658d04e8d96d87b90c", "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c",
%{ %{
"compiler" => "0.4.24", "compiler_version" => "0.4.24",
"contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }", "contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }",
"name" => "SimpleStorage", "name" => "SimpleStorage",
"optimization" => false "optimization" => false
@ -55,7 +55,7 @@ defmodule Explorer.SmartContract.Publisher do
%{ %{
address_hash: address_hash, address_hash: address_hash,
name: params["name"], name: params["name"],
compiler_version: params["compiler"], compiler_version: params["compiler_version"],
optimization: params["optimization"], optimization: params["optimization"],
contract_source_code: params["contract_source_code"], contract_source_code: params["contract_source_code"],
abi: abi abi: abi

@ -3,102 +3,116 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
Module responsible to compile the Solidity code of a given Smart Contract. Module responsible to compile the Solidity code of a given Smart Contract.
""" """
@doc ~S""" @doc """
Compiles a code in the solidity command line. Compiles a code in the solidity command line.
Returns a `Map`. Returns a `Map`.
## Examples ## Examples
iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run("SimpleStorage", "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }", false)
%{ iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run(
"contracts" => %{ ...> "SimpleStorage",
"SimpleStorage" => %{ ...> "v0.4.24+commit.e67f0147",
"SimpleStorage" => %{ ...> \"""
"abi" => [ ...> pragma solidity ^0.4.24;
%{ ...>
"constant" => false, ...> contract SimpleStorage {
"inputs" => [%{"name" => "x", "type" => "uint256"}], ...> uint storedData;
"name" => "set", ...>
"outputs" => [], ...> function set(uint x) public {
"payable" => false, ...> storedData = x;
"stateMutability" => "nonpayable", ...> }
"type" => "function" ...>
}, ...> function get() public constant returns (uint) {
%{ ...> return storedData;
"constant" => true, ...> }
"inputs" => [], ...> }
"name" => "get", ...> \""",
"outputs" => [%{"name" => "", "type" => "uint256"}], ...> false
"payable" => false, ...> )
"stateMutability" => "view", {
"type" => "function" :ok,
} %{
], "abi" => [
"evm" => %{ %{
"bytecode" => %{ "constant" => false,
"linkReferences" => %{}, "inputs" => [%{"name" => "x", "type" => "uint256"}],
"object" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029", "name" => "set",
"opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xDF DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 ADD PUSH18 0x72D01C000255D5C74C0EFCE764ADF7C4AE44 0x4d PUSH32 0x7E2ED852F6FB9B73DF5D00290000000000000000000000000000000000000000 ", "outputs" => [],
"sourceMap" => "25:157:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:157:0;;;;;;;" "payable" => false,
}, "stateMutability" => "nonpayable",
"deployedBytecode" => %{ "type" => "function"
"linkReferences" => %{}, },
"object" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029", %{
"opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 ADD PUSH18 0x72D01C000255D5C74C0EFCE764ADF7C4AE44 0x4d PUSH32 0x7E2ED852F6FB9B73DF5D00290000000000000000000000000000000000000000 ", "constant" => true,
"sourceMap" => "25:157:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66:46;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;113:67;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113:67:0;;;;;;;;;;;;;;;;;;;;;;;66:46;108:1;95:10;:14;;;;66:46;:::o;113:67::-;153:4;167:10;;160:17;;113:67;:::o" "inputs" => [],
}, "name" => "get",
"gasEstimates" => %{ "outputs" => [%{"name" => "", "type" => "uint256"}],
"creation" => %{ "payable" => false,
"codeDepositCost" => "44600", "stateMutability" => "view",
"executionCost" => "93", "type" => "function"
"totalCost" => "44693"
},
"external" => %{"get()" => "424", "set(uint256)" => "20205"}
}
},
"metadata" => "{\"compiler\":{\"version\":\"0.4.24+commit.e67f0147\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"SimpleStorage\":\"SimpleStorage\"},\"evmVersion\":\"byzantium\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"SimpleStorage\":{\"keccak256\":\"0x3f5ecc4c6077dffdfc98d9781295205833bf0558bc2a0c86fc3d5f246808ba34\",\"urls\":[\"bzzr://60d588b13340f26a038f51934f9b8c3cf3928372bc4358848a86960040a3a8e2\"]}},\"version\":1}"
} }
} ],
}, "bytecode" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820235fceab083d33bf112b473c85551306a29f32dcdc7e95b4dfdd697c1db188ec0029",
"sources" => %{"SimpleStorage" => %{"id" => 0}} "name" => "SimpleStorage",
"opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xDF DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x23 0x5f 0xce 0xab ADDMOD RETURNDATASIZE CALLER 0xbf GT 0x2b 0x47 EXTCODECOPY DUP6 SSTORE SGT MOD LOG2 SWAP16 ORIGIN 0xdc 0xdc PUSH31 0x95B4DFDD697C1DB188EC002900000000000000000000000000000000000000 "
}
} }
""" """
def run(name, code, optimization) do def run(name, compiler_version, code, optimize) do
{response, _status} = {response, _status} =
System.cmd( System.cmd(
Application.app_dir(:explorer, "priv/solc.bash"), "node",
[generate_settings(name, code, optimization)] [
Application.app_dir(:explorer, "priv/compile_solc.js"),
code,
compiler_version,
optimize_value(optimize)
]
) )
Jason.decode!(response) with %{"contracts" => contracts} <- Jason.decode!(response),
end %{"interface" => abi, "runtimeBytecode" => bytecode, "opcodes" => opcodes} <-
get_contract_info(contracts, name) do
@doc """ {
For more output options check the documentation. :ok,
https://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html#compiler-input-and-output-json-description %{
""" "abi" => Jason.decode!(abi),
def generate_settings(name, code, optimization) do "bytecode" => bytecode,
""" "name" => name,
{ "opcodes" => opcodes
"language": "Solidity",
"sources": {
"#{name}":
{
"content": "#{code}"
}
},
"settings": {
"optimizer": {
"enabled": #{optimization}
},
"outputSelection": {
"*": {
"*": [ "evm.bytecode", "evm.deployedBytecode", "evm.gasEstimates", "abi", "metadata" ]
}
} }
} }
} else
""" error ->
parse_error(error)
end
end end
def get_contract_info(contracts, _) when contracts == %{}, do: %{"errors" => []}
def get_contract_info(contracts, name) do
new_versions_name = ":" <> name
case contracts do
%{^new_versions_name => response} ->
response
%{^name => response} ->
response
_ ->
{:error, :name}
end
end
def parse_error({:error, :name} = error), do: error
def parse_error(%{"error" => error}), do: {:error, [error]}
def parse_error(%{"errors" => errors}), do: {:error, errors}
defp optimize_value(false), do: "0"
defp optimize_value("false"), do: "0"
defp optimize_value(true), do: "1"
defp optimize_value("true"), do: "1"
end end

@ -3,6 +3,8 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersion do
Adapter for fetching compiler versions from https://solc-bin.ethereum.org/bin/list.json. Adapter for fetching compiler versions from https://solc-bin.ethereum.org/bin/list.json.
""" """
@unsupported_versions ~w(0.1.1 0.1.2)
@doc """ @doc """
Fetches a list of compilers from the Ethereum Solidity API. Fetches a list of compilers from the Ethereum Solidity API.
""" """
@ -23,16 +25,30 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersion do
end end
defp format_data(json) do defp format_data(json) do
{:ok, releases} = versions =
json json
|> Jason.decode!() |> Jason.decode!()
|> Map.fetch("releases") |> Map.fetch!("builds")
|> remove_unsupported_versions()
|> format_versions()
|> Enum.reverse()
["latest" | versions]
end
defp remove_unsupported_versions(builds) do
Enum.reject(builds, fn %{"version" => version} ->
Enum.member?(@unsupported_versions, version)
end)
end
releases defp format_versions(builds) do
|> Map.to_list() Enum.map(builds, fn build ->
|> Enum.map(fn {key, _value} -> {key, key} end) build
|> Enum.sort() |> Map.fetch!("path")
|> Enum.reverse() |> String.replace_prefix("soljson-", "")
|> String.replace_suffix(".js", "")
end)
end end
defp decode_json(json) do defp decode_json(json) do

@ -11,32 +11,36 @@ defmodule Explorer.SmartContract.Verifier do
alias Explorer.SmartContract.Solidity.CodeCompiler alias Explorer.SmartContract.Solidity.CodeCompiler
def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name} def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name}
def evaluate_authenticity(_, %{"contract_source_code" => ""}), do: {:error, :contract_source_code}
def evaluate_authenticity(_, %{"contract_source_code" => ""}),
do: {:error, :contract_source_code}
def evaluate_authenticity(address_hash, %{ def evaluate_authenticity(address_hash, %{
"name" => name, "name" => name,
"contract_source_code" => contract_source_code, "contract_source_code" => contract_source_code,
"optimization" => optimization "optimization" => optimization,
"compiler_version" => compiler_version
}) do }) do
solc_output = CodeCompiler.run(name, contract_source_code, optimization) solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization)
compare_bytecodes(solc_output, address_hash)
end
defp compare_bytecodes({:error, :name}, _), do: {:error, :name}
defp compare_bytecodes({:error, _}, _), do: {:error, :compilation}
case solc_output do defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash) do
%{ generated_bytecode = extract_bytecode(bytecode)
"contracts" => %{
^name => %{ "0x" <> blockchain_bytecode =
^name => %{ address_hash
"abi" => abi, |> Chain.smart_contract_bytecode()
"evm" => %{ |> extract_bytecode
"bytecode" => %{"object" => bytecode}
}
}
}
}
} ->
compare_bytecodes(address_hash, abi, bytecode)
_ -> if generated_bytecode == blockchain_bytecode do
{:error, :compilation} {:ok, %{abi: abi}}
else
{:error, :generated_bytecode}
end end
end end
@ -56,19 +60,4 @@ defmodule Explorer.SmartContract.Verifier do
bytecode bytecode
end end
defp compare_bytecodes(address_hash, abi, bytecode) do
generated_bytecode = extract_bytecode(bytecode)
"0x" <> blockchain_bytecode =
address_hash
|> Chain.smart_contract_bytecode()
|> extract_bytecode
if generated_bytecode == blockchain_bytecode do
{:ok, %{abi: abi}}
else
{:error, :generated_bytecode}
end
end
end end

@ -0,0 +1,18 @@
{
"repository": {
"type": "git",
"url": "git+https://github.com/poanetwork/poa-explorer.git"
},
"private": true,
"name": "poa-explorer",
"author": "POA Network",
"license": "GPL-3.0",
"engines": {
"node": "9.x",
"npm": "5.x"
},
"scripts": {},
"dependencies": {
"solc-js": "^0.4.20-browser.1"
}
}

@ -0,0 +1,15 @@
#!/usr/bin/env node
const solc = require('solc-js');
var sourceCode = process.argv[2];
var version = process.argv[3];
var optimize = process.argv[4];
var compiled_code = solc.loadRemoteVersion(version, function (err, solcSnapshot) {
if (err) {
console.log(JSON.stringify(err));
} else {
console.log(JSON.stringify(solcSnapshot.compile(sourceCode, optimize)));
}
});

@ -1,3 +0,0 @@
#!/bin/bash
echo "$1" | solc --standard-json

@ -5,43 +5,29 @@ defmodule Explorer.SmartContract.PublisherTest do
doctest Explorer.SmartContract.Publisher doctest Explorer.SmartContract.Publisher
alias Explorer.Chain.{SmartContract, Hash} alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.Publisher alias Explorer.SmartContract.Publisher
alias Explorer.Factory
describe "publish/2" do describe "publish/2" do
test "with valid data creates a smart_contract" do test "with valid data creates a smart_contract" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_code_info = Factory.contract_code_info()
smart_contract_bytecode = contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction_create,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
valid_attrs = %{ valid_attrs = %{
"contract_source_code" => "contract_source_code" => contract_code_info.source_code,
"pragma solidity ^0.4.23;\r\n\r\ncontract SimpleStorage {\r\n uint storedData;\r\n\r\n function set(uint x) public {\r\n storedData = x;\r\n }\r\n\r\n function get() public constant returns (uint) {\r\n return storedData;\r\n }\r\n}", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:ok, %SmartContract{} = smart_contract} = Publisher.publish(address_hash, valid_attrs) response = Publisher.publish(contract_address.hash, valid_attrs)
assert {:ok, %SmartContract{} = smart_contract} = response
assert smart_contract.address_hash == contract_address.hash
assert smart_contract.name == valid_attrs["name"] assert smart_contract.name == valid_attrs["name"]
assert Hash.to_string(smart_contract.address_hash) == address_hash assert smart_contract.compiler_version == valid_attrs["compiler_version"]
assert smart_contract.compiler_version == valid_attrs["compiler"]
assert smart_contract.optimization == valid_attrs["optimization"] assert smart_contract.optimization == valid_attrs["optimization"]
assert smart_contract.contract_source_code == valid_attrs["contract_source_code"] assert smart_contract.contract_source_code == valid_attrs["contract_source_code"]
assert smart_contract.abi != nil assert smart_contract.abi != nil
@ -52,7 +38,7 @@ defmodule Explorer.SmartContract.PublisherTest do
invalid_attrs = %{ invalid_attrs = %{
"contract_source_code" => "", "contract_source_code" => "",
"compiler" => "", "compiler_version" => "",
"name" => "", "name" => "",
"optimization" => "" "optimization" => ""
} }

@ -4,15 +4,56 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
doctest Explorer.SmartContract.Solidity.CodeCompiler doctest Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.SmartContract.Solidity.CodeCompiler alias Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.Factory
describe "run/2" do describe "run/2" do
test "compiles a smart contract using the solidity command line" do setup do
{:ok, contract_code_info: Factory.contract_code_info()}
end
test "compiles the latest solidity version", %{contract_code_info: contract_code_info} do
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
contract_code_info.source_code,
contract_code_info.optimized
)
assert {:ok,
%{
"abi" => _,
"bytecode" => _,
"name" => _,
"opcodes" => _
}} = response
end
test "compiles a optimized smart contract", %{contract_code_info: contract_code_info} do
optimize = true
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
contract_code_info.source_code,
optimize
)
assert {:ok,
%{
"abi" => _,
"bytecode" => _,
"name" => _,
"opcodes" => _
}} = response
end
test "compile in an older solidity version" do
optimize = false
name = "SimpleStorage" name = "SimpleStorage"
optimization = false
code = """ code = """
pragma solidity ^0.4.24;
contract SimpleStorage { contract SimpleStorage {
uint storedData; uint storedData;
@ -26,48 +67,74 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
} }
""" """
response = CodeCompiler.run(name, code, optimization) version = "v0.1.3-nightly.2015.9.25+commit.4457170"
assert %{ response = CodeCompiler.run(name, version, code, optimize)
"contracts" => %{
^name => %{ assert {:ok,
^name => %{ %{
"abi" => _, "abi" => _,
"evm" => %{ "bytecode" => _,
"bytecode" => %{"object" => _} "name" => _,
} "opcodes" => _
} }} = response
} end
}
} = response test "returns a list of errors the compilation isn't possible", %{
contract_code_info: contract_code_info
} do
wrong_code = "pragma solidity ^0.4.24; cont SimpleStorage { "
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
wrong_code,
contract_code_info.optimized
)
assert {:error, errors} = response
assert is_list(errors)
end end
end end
describe "generate_settings/2" do describe "get_contract_info/1" do
test "creates a json file with the solidity compiler expected settings" do test "return name error when the Contract name doesn't match" do
name = "SimpleStorage" name = "Name"
optimization = false different_name = "diff_name"
code = """ response = CodeCompiler.get_contract_info(%{name => %{}}, different_name)
pragma solidity ^0.4.24;
contract SimpleStorage { assert {:error, :name} == response
uint storedData; end
function set(uint x) public { test "returns an empty list of errors for empty info" do
storedData = x; name = "Name"
}
function get() public constant returns (uint) { response = CodeCompiler.get_contract_info(%{}, name)
return storedData;
} assert %{"errors" => []} == response
} end
"""
test "the contract info is returned when the name matches" do
contract_inner_info = %{"abi" => %{}, "bytecode" => "", "opcodes" => ""}
name = "Name"
contract_info = %{name => contract_inner_info}
response = CodeCompiler.get_contract_info(contract_info, name)
assert contract_inner_info == response
end
test "the contract info is returned when the name matches with a `:` sufix" do
name = "Name"
name_with_sufix = ":Name"
contract_inner_info = %{"abi" => %{}, "bytecode" => "", "opcodes" => ""}
contract_info = %{name_with_sufix => contract_inner_info}
generated = CodeCompiler.generate_settings(name, code, optimization) response = CodeCompiler.get_contract_info(contract_info, name)
assert String.contains?(generated, "contract SimpleStorage") == true assert contract_inner_info == response
assert String.contains?(generated, "settings") == true
end end
end end
end end

@ -24,7 +24,19 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersionTest do
end) end)
assert {:ok, versions} = CompilerVersion.fetch_versions() assert {:ok, versions} = CompilerVersion.fetch_versions()
assert Enum.any?(versions, fn item -> item == {"0.4.9", "0.4.9"} end) == true assert Enum.any?(versions, fn item -> item == "v0.4.9+commit.364da425" end) == true
end
test "always returns 'latest' in the first item", %{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 List.first(versions) == "latest"
end end
test "returns error when list of versions is not available", %{bypass: bypass} do test "returns error when list of versions is not available", %{bypass: bypass} do

@ -5,84 +5,57 @@ defmodule Explorer.SmartContract.VerifierTest do
doctest Explorer.SmartContract.Verifier doctest Explorer.SmartContract.Verifier
alias Explorer.SmartContract.Verifier alias Explorer.SmartContract.Verifier
alias Explorer.Factory
describe "evaluate_authenticity/2" do describe "evaluate_authenticity/2" do
test "verifies the generated bytecode against bytecode retrieved from the blockchain" do setup do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" {:ok, contract_code_info: Factory.contract_code_info()}
end
smart_contract_bytecode =
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert( test "verifies the generated bytecode against bytecode retrieved from the blockchain", %{
:internal_transaction_create, contract_code_info: contract_code_info
transaction: transaction, } do
index: 0, contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
params = %{ params = %{
"contract_source_code" => "contract_source_code" => contract_code_info.source_code,
"pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(address_hash, params) assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
assert abi != nil assert abi != nil
end end
test "returns error when bytecoed doesn't match" do test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
wrong_smart_contract_bytecode = different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}"
"0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058207722b6ddfe522b31e50b878ced2f22d051e8e2cd19be7b4fba9686602b90ba2b0029"
created_contract_address = insert(:address, hash: address_hash, contract_code: wrong_smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction_create,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: wrong_smart_contract_bytecode
)
params = %{ params = %{
"contract_source_code" => "contract_source_code" => different_code,
"pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:error, :generated_bytecode} = Verifier.evaluate_authenticity(address_hash, params) response = Verifier.evaluate_authenticity(contract_address.hash, params)
assert {:error, :generated_bytecode} = response
end end
test "returns error when there is a compilation problem" do test "returns error when there is a compilation problem", %{contract_code_info: contract_code_info} do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
params = %{ params = %{
"contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { ", "contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { ",
"compiler" => "0.4.24", "compiler_version" => contract_code_info.version,
"name" => "SimpleStorage", "name" => contract_code_info.name,
"optimization" => false "optimization" => contract_code_info.optimized
} }
assert {:error, :compilation} = Verifier.evaluate_authenticity(address_hash, params) assert {:error, :compilation} = Verifier.evaluate_authenticity(contract_address.hash, params)
end end
end end

@ -29,6 +29,38 @@ defmodule Explorer.Factory do
} }
end end
def contract_address_factory do
%Address{
hash: address_hash(),
contract_code: Map.fetch!(contract_code_info(), :bytecode)
}
end
def contract_code_info do
%{
bytecode:
"0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820f65a3adc1cfb055013d1dc37d0fe98676e2a5963677fa7541a10386d163446680029",
name: "SimpleStorage",
source_code: """
pragma solidity ^0.4.24;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public constant returns (uint) {
return storedData;
}
}
""",
version: "v0.4.24+commit.e67f0147",
optimized: false
}
end
def address_hash do def address_hash do
{:ok, address_hash} = {:ok, address_hash} =
"address_hash" "address_hash"

@ -5689,6 +5689,302 @@
"urls": [ "urls": [
"bzzr://965ce40ed5e4037a3b3916873b113052129082efec45f9aba767658515264bc5" "bzzr://965ce40ed5e4037a3b3916873b113052129082efec45f9aba767658515264bc5"
] ]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.14+commit.7a669b39.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.14",
"build": "commit.7a669b39",
"longVersion": "0.4.24-nightly.2018.5.14+commit.7a669b39",
"keccak256": "0xd6877c4e6919906f0c2ec5eebc8b54bd8abecf36619f1b9de53118d66890c4c2",
"urls": [
"bzzr://83393f31311c2cd49f4c8564a9fbc6962be548a73c79a5967eb7423ee5cf59d7"
]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.15+commit.b8b46099.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.15",
"build": "commit.b8b46099",
"longVersion": "0.4.24-nightly.2018.5.15+commit.b8b46099",
"keccak256": "0xeea56c1218e694e86024a3e18b04f5f428e182e39cfa94d0f4e21e5b2b3675cc",
"urls": [
"bzzr://dbaaa698d20207fb480f5571ee110d2f5f9fc4825ec5fb7c1d0a66c235541d1e"
]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.16+commit.7f965c86.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.16",
"build": "commit.7f965c86",
"longVersion": "0.4.24-nightly.2018.5.16+commit.7f965c86",
"keccak256": "0x7e34ded082f4403f672626691c86bac90cf3127047bdadd92218fcad9c5cc05e",
"urls": [
"bzzr://cfa47b4d8d75df10651343eb3ef3609d6b1176a35a0c97faee45abeb7b033cf3"
]
},
{
"path": "soljson-v0.4.24+commit.e67f0147.js",
"version": "0.4.24",
"build": "commit.e67f0147",
"longVersion": "0.4.24+commit.e67f0147",
"keccak256": "0xee322e8f3117fcd7c196e88407d938846c096a3c62a51debd8a646f3aa228fcb",
"urls": [
"bzzr://bbcf75b3549aaa4b68bdd805e5c5b8a0b0be6a964e068b7ef36c48431f44e8e1"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.16+commit.3897c367.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.16",
"build": "commit.3897c367",
"longVersion": "0.4.25-nightly.2018.5.16+commit.3897c367",
"keccak256": "0x542d4ee7433cc87b0af481c0576c0eaa1e039564920cabaf05c470129028adab",
"urls": [
"bzzr://59a32bef8105739bcfd4c510bfd79af4c8ed8c6a7044cc35226dcf728730c66e"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.17+commit.4aa2f036.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.17",
"build": "commit.4aa2f036",
"longVersion": "0.4.25-nightly.2018.5.17+commit.4aa2f036",
"keccak256": "0xdb0c3ad580eece0e4be735bc393511d5c6da3a43e4d9bdae4bb301759db9a48b",
"urls": [
"bzzr://d7518a74bdf87800dab785598f1194800cf74729b31bb2f2cf56884285bd3d7b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.18+commit.4d7b092c.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.18",
"build": "commit.4d7b092c",
"longVersion": "0.4.25-nightly.2018.5.18+commit.4d7b092c",
"keccak256": "0xdf46b3a863c003d7e5e4e5629dc95c120c34c2fc2379dfe686a91b0b513a0cf6",
"urls": [
"bzzr://a40273ce36779aa9fa27bcda851a6bf9c7919830ebb27fd73e10e539a502a4dc"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.21+commit.e97f9b6b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.21",
"build": "commit.e97f9b6b",
"longVersion": "0.4.25-nightly.2018.5.21+commit.e97f9b6b",
"keccak256": "0xb5b57bc72c77a76e277e7eac82d041dfaa251288f727c13d1b22bbfbda039e32",
"urls": [
"bzzr://058835dd41e4819be08eede51f46b0c75311f95b1e1079891d6d888d94074da6"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.22+commit.849b1bd5.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.22",
"build": "commit.849b1bd5",
"longVersion": "0.4.25-nightly.2018.5.22+commit.849b1bd5",
"keccak256": "0x2770bcff9311f4cc1b11b31e8e186ce205a7376353979c9a3b122a00f11ba06d",
"urls": [
"bzzr://9a7d1a775538ae6f416cef602b01edb0af53c3f740c2a321b8a7077af9c0f55e"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.23+commit.18c651b7.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.23",
"build": "commit.18c651b7",
"longVersion": "0.4.25-nightly.2018.5.23+commit.18c651b7",
"keccak256": "0x8b21b478706c069b19746b7d088396ad1a7323acca051f7e3c9065ad172fff19",
"urls": [
"bzzr://254ef850416cf8862bf2a9495f202099f56e6d39fc03fd177d2aefe5a0d9643c"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.28+commit.c223b03.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.28",
"build": "commit.c223b03",
"longVersion": "0.4.25-nightly.2018.5.28+commit.c223b03",
"keccak256": "0x7b2fd7abeb5ee053f462ecb6e075b5435c5903ffc337956af5d5174d787c958e",
"urls": [
"bzzr://001ab758e76c6a7368d943543d382557210c5edf37ffbdcaaa627f60319f8bc5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.30+commit.3f3d6df2.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.30",
"build": "commit.3f3d6df2",
"longVersion": "0.4.25-nightly.2018.5.30+commit.3f3d6df2",
"keccak256": "0xb8717d5ddd7cb2f8516b7e7bf0cae3802cd89659d3c2b408f5c9f4ce67545e9f",
"urls": [
"bzzr://966adc290ef6f10203304c0866ad7c4bd233a93c7e74639b53647263fd02c71b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.3+commit.ef8fb63b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.3",
"build": "commit.ef8fb63b",
"longVersion": "0.4.25-nightly.2018.6.3+commit.ef8fb63b",
"keccak256": "0x6e5eb8454f1e6f6248f609d839e2d459842326db86536f138341555b2985b58d",
"urls": [
"bzzr://31d1b91ba0efa44ea689a2df2637de69fc09dc1a998a81df9fd1aad7514b9e65"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.4+commit.a074d84.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.4",
"build": "commit.a074d84",
"longVersion": "0.4.25-nightly.2018.6.4+commit.a074d84",
"keccak256": "0x257b4782376e9f044df5126869745811fa2a00bce2d9fca3e0665d81244dead4",
"urls": [
"bzzr://9a46af1a168690a684139ca2d2d4550932f3c11ab7a3d9493491be45319e0e9b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.5+commit.7422cd73.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.5",
"build": "commit.7422cd73",
"longVersion": "0.4.25-nightly.2018.6.5+commit.7422cd73",
"keccak256": "0x36271bbc780a45b1b5ed82f6e8e09a02caf78557a9548962e6162032f1a4014a",
"urls": [
"bzzr://dc36676cf21c961dfd52651b82c85219f1843f578489195dcd6b6f48947d60b9"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.6+commit.59b35fa5.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.6",
"build": "commit.59b35fa5",
"longVersion": "0.4.25-nightly.2018.6.6+commit.59b35fa5",
"keccak256": "0xcaa82fac0cbcf2e35782e45745cf830f97eee0bf27bba85d24de967d3e863e71",
"urls": [
"bzzr://f631082277241bdbe1fcd92783f4864d60c7dd16bb96ff78a84e73cfbd7acce8"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.7+commit.ddd256a6.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.7",
"build": "commit.ddd256a6",
"longVersion": "0.4.25-nightly.2018.6.7+commit.ddd256a6",
"keccak256": "0x164b5cbbab21103155cce12b2e6e819d7f6e748cdcf2ece5194ab4e9e2129ca3",
"urls": [
"bzzr://3f305063ff8f7c7fb04fb7071120b3adae90a741e7ccbacc07d3535724f973f5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.8+commit.81c5a6e4.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.8",
"build": "commit.81c5a6e4",
"longVersion": "0.4.25-nightly.2018.6.8+commit.81c5a6e4",
"keccak256": "0x6d319de59f80795dc65ff9c71cbc88d5433664c2e208f6bc1ca3bcca011dd69e",
"urls": [
"bzzr://ba5f458fc3a05465d52fe2e4502a5b2517cdde3ddaa1da3c6229494d2ee3f841"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.11+commit.d0355619.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.11",
"build": "commit.d0355619",
"longVersion": "0.4.25-nightly.2018.6.11+commit.d0355619",
"keccak256": "0xc61567f505486fd9a7907b05e10ca297fe5d0f7f021c070449ac541795d781b3",
"urls": [
"bzzr://990aad9205b4293bf6923f7d6abac9416928dccde529b7df52c379e1432e3dcc"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.12+commit.56a965ea.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.12",
"build": "commit.56a965ea",
"longVersion": "0.4.25-nightly.2018.6.12+commit.56a965ea",
"keccak256": "0xdab0a9f25c5f5fb9f7a824eb01225ebf0f73d744b33049587b642179485fe059",
"urls": [
"bzzr://5596d6d153d32f43557d738d9de4343e880fed7030d0b1c93792fa57c69dc8e5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.13+commit.3055e4ca.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.13",
"build": "commit.3055e4ca",
"longVersion": "0.4.25-nightly.2018.6.13+commit.3055e4ca",
"keccak256": "0x5332a1fa2f9e24d39a5013b117552c2adf7e130d6d5ea96d86db8f99b2126cbb",
"urls": [
"bzzr://0b5c9b9ab9d15edf63fd9a14ec32d684c8a980f49f80d274d96edf0112ba30b9"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.14+commit.baeabe1c.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.14",
"build": "commit.baeabe1c",
"longVersion": "0.4.25-nightly.2018.6.14+commit.baeabe1c",
"keccak256": "0x3a1ea681afc4be4ec049258d7c6d262e251e46bbb571b13e78b3ed11875dc040",
"urls": [
"bzzr://9b80ae9f183780cea4f6e11c47a6dd2d845399da0537518fc834cbd8abba1d3a"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.17+commit.1692f78b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.17",
"build": "commit.1692f78b",
"longVersion": "0.4.25-nightly.2018.6.17+commit.1692f78b",
"keccak256": "0xf4f2d9990c605f24f4f8217f6c1249150b0709e76ed0f785af4a163f96d231ab",
"urls": [
"bzzr://a73ad38f658292182d399010fbfbb6ac1069fa4b2e59b192bb1e04987aa074ca"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.18+commit.4247b004.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.18",
"build": "commit.4247b004",
"longVersion": "0.4.25-nightly.2018.6.18+commit.4247b004",
"keccak256": "0xea2f1c0ab2bb9b8fe910d611f3a49e5fd37a3eb6d9adf9f5f8f58f9b488cffa5",
"urls": [
"bzzr://fb554bd8f06cdb7d84e68a9900dca8c0a1cfcbd9a1a60912f95f8b6005539f51"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.19+commit.c72e04c3.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.19",
"build": "commit.c72e04c3",
"longVersion": "0.4.25-nightly.2018.6.19+commit.c72e04c3",
"keccak256": "0x2a0509619ae9d8e48c995729031dcebcf9eec3f331db383f183e311e548e95c3",
"urls": [
"bzzr://086d626be661d624f875e9a06c8308ca29cd0a1e5e96c098518fd6f458266a04"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.20+commit.ba7fbf11.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.20",
"build": "commit.ba7fbf11",
"longVersion": "0.4.25-nightly.2018.6.20+commit.ba7fbf11",
"keccak256": "0x4d54a840997e7357d832ef48fcf254aa73d3cbd98ba2a2db3f4a334343382da7",
"urls": [
"bzzr://1fe442eebadd93850fb579baa2772038a8c9b16c86cbfa41337cccacb1f58f9f"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.21+commit.d104718.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.21",
"build": "commit.d104718",
"longVersion": "0.4.25-nightly.2018.6.21+commit.d104718",
"keccak256": "0x02d92eda9e226921dbc2daa5614718af522b398365698daf38acdac20c49f81a",
"urls": [
"bzzr://0005e5682dd04228df8307d747263acf0c441fcadccceeb48c8174e92783aed2"
]
} }
], ],
"releases": { "releases": {

@ -31,9 +31,9 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<%= label f, :compiler, "Compiler" %> <%= label f, :compiler_version, "Compiler" %>
<%= select f, :compiler, @compiler_versions, class: "form-control", selected: "0.4.24" %> <%= select f, :compiler_version, @compiler_versions, class: "form-control", selected: "latest" %>
<%= error_tag f, :compiler %> <%= error_tag f, :compiler_version %>
</div> </div>
<div class="form-group"> <div class="form-group">

@ -4,6 +4,7 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
import Wallaby.Query import Wallaby.Query
alias Plug.Conn alias Plug.Conn
alias Explorer.Factory
setup do setup do
bypass = Bypass.open() bypass = Bypass.open()
@ -16,51 +17,19 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
test "users validates smart contract", %{session: session, bypass: bypass} do test "users validates smart contract", %{session: session, bypass: bypass} do
Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, solc_bin_versions()) end) Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, solc_bin_versions()) end)
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" %{name: name, source_code: source_code, bytecode: bytecode, version: version} = Factory.contract_code_info()
smart_contract_bytecode = contract_address = insert(:contract_address, contract_code: bytecode)
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
code = """
pragma solidity ^0.4.24;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public constant returns (uint) {
return storedData;
}
}
"""
session session
|> visit("/en/addresses/#{address_hash}/contract_verifications/new") |> visit("/en/addresses/#{contract_address.hash}/contract_verifications/new")
|> fill_in(text_field("Contract Name"), with: "SimpleStorage") |> fill_in(text_field("Contract Name"), with: name)
|> click(option("0.4.24")) |> click(option(version))
|> click(radio_button("No")) |> click(radio_button("No"))
|> fill_in(text_field("Enter the Solidity Contract Code below"), with: code) |> fill_in(text_field("Enter the Solidity Contract Code below"), with: source_code)
|> click(button("Verify and publish")) |> click(button("Verify and publish"))
assert current_path(session) =~ ~r/\/en\/addresses\/#{address_hash}\/contracts/ assert current_path(session) =~ ~r/\/en\/addresses\/#{contract_address.hash}\/contracts/
end end
test "with invalid data shows error messages", %{session: session, bypass: bypass} do test "with invalid data shows error messages", %{session: session, bypass: bypass} do

@ -5689,6 +5689,302 @@
"urls": [ "urls": [
"bzzr://965ce40ed5e4037a3b3916873b113052129082efec45f9aba767658515264bc5" "bzzr://965ce40ed5e4037a3b3916873b113052129082efec45f9aba767658515264bc5"
] ]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.14+commit.7a669b39.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.14",
"build": "commit.7a669b39",
"longVersion": "0.4.24-nightly.2018.5.14+commit.7a669b39",
"keccak256": "0xd6877c4e6919906f0c2ec5eebc8b54bd8abecf36619f1b9de53118d66890c4c2",
"urls": [
"bzzr://83393f31311c2cd49f4c8564a9fbc6962be548a73c79a5967eb7423ee5cf59d7"
]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.15+commit.b8b46099.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.15",
"build": "commit.b8b46099",
"longVersion": "0.4.24-nightly.2018.5.15+commit.b8b46099",
"keccak256": "0xeea56c1218e694e86024a3e18b04f5f428e182e39cfa94d0f4e21e5b2b3675cc",
"urls": [
"bzzr://dbaaa698d20207fb480f5571ee110d2f5f9fc4825ec5fb7c1d0a66c235541d1e"
]
},
{
"path": "soljson-v0.4.24-nightly.2018.5.16+commit.7f965c86.js",
"version": "0.4.24",
"prerelease": "nightly.2018.5.16",
"build": "commit.7f965c86",
"longVersion": "0.4.24-nightly.2018.5.16+commit.7f965c86",
"keccak256": "0x7e34ded082f4403f672626691c86bac90cf3127047bdadd92218fcad9c5cc05e",
"urls": [
"bzzr://cfa47b4d8d75df10651343eb3ef3609d6b1176a35a0c97faee45abeb7b033cf3"
]
},
{
"path": "soljson-v0.4.24+commit.e67f0147.js",
"version": "0.4.24",
"build": "commit.e67f0147",
"longVersion": "0.4.24+commit.e67f0147",
"keccak256": "0xee322e8f3117fcd7c196e88407d938846c096a3c62a51debd8a646f3aa228fcb",
"urls": [
"bzzr://bbcf75b3549aaa4b68bdd805e5c5b8a0b0be6a964e068b7ef36c48431f44e8e1"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.16+commit.3897c367.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.16",
"build": "commit.3897c367",
"longVersion": "0.4.25-nightly.2018.5.16+commit.3897c367",
"keccak256": "0x542d4ee7433cc87b0af481c0576c0eaa1e039564920cabaf05c470129028adab",
"urls": [
"bzzr://59a32bef8105739bcfd4c510bfd79af4c8ed8c6a7044cc35226dcf728730c66e"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.17+commit.4aa2f036.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.17",
"build": "commit.4aa2f036",
"longVersion": "0.4.25-nightly.2018.5.17+commit.4aa2f036",
"keccak256": "0xdb0c3ad580eece0e4be735bc393511d5c6da3a43e4d9bdae4bb301759db9a48b",
"urls": [
"bzzr://d7518a74bdf87800dab785598f1194800cf74729b31bb2f2cf56884285bd3d7b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.18+commit.4d7b092c.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.18",
"build": "commit.4d7b092c",
"longVersion": "0.4.25-nightly.2018.5.18+commit.4d7b092c",
"keccak256": "0xdf46b3a863c003d7e5e4e5629dc95c120c34c2fc2379dfe686a91b0b513a0cf6",
"urls": [
"bzzr://a40273ce36779aa9fa27bcda851a6bf9c7919830ebb27fd73e10e539a502a4dc"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.21+commit.e97f9b6b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.21",
"build": "commit.e97f9b6b",
"longVersion": "0.4.25-nightly.2018.5.21+commit.e97f9b6b",
"keccak256": "0xb5b57bc72c77a76e277e7eac82d041dfaa251288f727c13d1b22bbfbda039e32",
"urls": [
"bzzr://058835dd41e4819be08eede51f46b0c75311f95b1e1079891d6d888d94074da6"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.22+commit.849b1bd5.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.22",
"build": "commit.849b1bd5",
"longVersion": "0.4.25-nightly.2018.5.22+commit.849b1bd5",
"keccak256": "0x2770bcff9311f4cc1b11b31e8e186ce205a7376353979c9a3b122a00f11ba06d",
"urls": [
"bzzr://9a7d1a775538ae6f416cef602b01edb0af53c3f740c2a321b8a7077af9c0f55e"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.23+commit.18c651b7.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.23",
"build": "commit.18c651b7",
"longVersion": "0.4.25-nightly.2018.5.23+commit.18c651b7",
"keccak256": "0x8b21b478706c069b19746b7d088396ad1a7323acca051f7e3c9065ad172fff19",
"urls": [
"bzzr://254ef850416cf8862bf2a9495f202099f56e6d39fc03fd177d2aefe5a0d9643c"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.28+commit.c223b03.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.28",
"build": "commit.c223b03",
"longVersion": "0.4.25-nightly.2018.5.28+commit.c223b03",
"keccak256": "0x7b2fd7abeb5ee053f462ecb6e075b5435c5903ffc337956af5d5174d787c958e",
"urls": [
"bzzr://001ab758e76c6a7368d943543d382557210c5edf37ffbdcaaa627f60319f8bc5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.5.30+commit.3f3d6df2.js",
"version": "0.4.25",
"prerelease": "nightly.2018.5.30",
"build": "commit.3f3d6df2",
"longVersion": "0.4.25-nightly.2018.5.30+commit.3f3d6df2",
"keccak256": "0xb8717d5ddd7cb2f8516b7e7bf0cae3802cd89659d3c2b408f5c9f4ce67545e9f",
"urls": [
"bzzr://966adc290ef6f10203304c0866ad7c4bd233a93c7e74639b53647263fd02c71b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.3+commit.ef8fb63b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.3",
"build": "commit.ef8fb63b",
"longVersion": "0.4.25-nightly.2018.6.3+commit.ef8fb63b",
"keccak256": "0x6e5eb8454f1e6f6248f609d839e2d459842326db86536f138341555b2985b58d",
"urls": [
"bzzr://31d1b91ba0efa44ea689a2df2637de69fc09dc1a998a81df9fd1aad7514b9e65"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.4+commit.a074d84.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.4",
"build": "commit.a074d84",
"longVersion": "0.4.25-nightly.2018.6.4+commit.a074d84",
"keccak256": "0x257b4782376e9f044df5126869745811fa2a00bce2d9fca3e0665d81244dead4",
"urls": [
"bzzr://9a46af1a168690a684139ca2d2d4550932f3c11ab7a3d9493491be45319e0e9b"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.5+commit.7422cd73.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.5",
"build": "commit.7422cd73",
"longVersion": "0.4.25-nightly.2018.6.5+commit.7422cd73",
"keccak256": "0x36271bbc780a45b1b5ed82f6e8e09a02caf78557a9548962e6162032f1a4014a",
"urls": [
"bzzr://dc36676cf21c961dfd52651b82c85219f1843f578489195dcd6b6f48947d60b9"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.6+commit.59b35fa5.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.6",
"build": "commit.59b35fa5",
"longVersion": "0.4.25-nightly.2018.6.6+commit.59b35fa5",
"keccak256": "0xcaa82fac0cbcf2e35782e45745cf830f97eee0bf27bba85d24de967d3e863e71",
"urls": [
"bzzr://f631082277241bdbe1fcd92783f4864d60c7dd16bb96ff78a84e73cfbd7acce8"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.7+commit.ddd256a6.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.7",
"build": "commit.ddd256a6",
"longVersion": "0.4.25-nightly.2018.6.7+commit.ddd256a6",
"keccak256": "0x164b5cbbab21103155cce12b2e6e819d7f6e748cdcf2ece5194ab4e9e2129ca3",
"urls": [
"bzzr://3f305063ff8f7c7fb04fb7071120b3adae90a741e7ccbacc07d3535724f973f5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.8+commit.81c5a6e4.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.8",
"build": "commit.81c5a6e4",
"longVersion": "0.4.25-nightly.2018.6.8+commit.81c5a6e4",
"keccak256": "0x6d319de59f80795dc65ff9c71cbc88d5433664c2e208f6bc1ca3bcca011dd69e",
"urls": [
"bzzr://ba5f458fc3a05465d52fe2e4502a5b2517cdde3ddaa1da3c6229494d2ee3f841"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.11+commit.d0355619.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.11",
"build": "commit.d0355619",
"longVersion": "0.4.25-nightly.2018.6.11+commit.d0355619",
"keccak256": "0xc61567f505486fd9a7907b05e10ca297fe5d0f7f021c070449ac541795d781b3",
"urls": [
"bzzr://990aad9205b4293bf6923f7d6abac9416928dccde529b7df52c379e1432e3dcc"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.12+commit.56a965ea.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.12",
"build": "commit.56a965ea",
"longVersion": "0.4.25-nightly.2018.6.12+commit.56a965ea",
"keccak256": "0xdab0a9f25c5f5fb9f7a824eb01225ebf0f73d744b33049587b642179485fe059",
"urls": [
"bzzr://5596d6d153d32f43557d738d9de4343e880fed7030d0b1c93792fa57c69dc8e5"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.13+commit.3055e4ca.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.13",
"build": "commit.3055e4ca",
"longVersion": "0.4.25-nightly.2018.6.13+commit.3055e4ca",
"keccak256": "0x5332a1fa2f9e24d39a5013b117552c2adf7e130d6d5ea96d86db8f99b2126cbb",
"urls": [
"bzzr://0b5c9b9ab9d15edf63fd9a14ec32d684c8a980f49f80d274d96edf0112ba30b9"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.14+commit.baeabe1c.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.14",
"build": "commit.baeabe1c",
"longVersion": "0.4.25-nightly.2018.6.14+commit.baeabe1c",
"keccak256": "0x3a1ea681afc4be4ec049258d7c6d262e251e46bbb571b13e78b3ed11875dc040",
"urls": [
"bzzr://9b80ae9f183780cea4f6e11c47a6dd2d845399da0537518fc834cbd8abba1d3a"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.17+commit.1692f78b.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.17",
"build": "commit.1692f78b",
"longVersion": "0.4.25-nightly.2018.6.17+commit.1692f78b",
"keccak256": "0xf4f2d9990c605f24f4f8217f6c1249150b0709e76ed0f785af4a163f96d231ab",
"urls": [
"bzzr://a73ad38f658292182d399010fbfbb6ac1069fa4b2e59b192bb1e04987aa074ca"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.18+commit.4247b004.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.18",
"build": "commit.4247b004",
"longVersion": "0.4.25-nightly.2018.6.18+commit.4247b004",
"keccak256": "0xea2f1c0ab2bb9b8fe910d611f3a49e5fd37a3eb6d9adf9f5f8f58f9b488cffa5",
"urls": [
"bzzr://fb554bd8f06cdb7d84e68a9900dca8c0a1cfcbd9a1a60912f95f8b6005539f51"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.19+commit.c72e04c3.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.19",
"build": "commit.c72e04c3",
"longVersion": "0.4.25-nightly.2018.6.19+commit.c72e04c3",
"keccak256": "0x2a0509619ae9d8e48c995729031dcebcf9eec3f331db383f183e311e548e95c3",
"urls": [
"bzzr://086d626be661d624f875e9a06c8308ca29cd0a1e5e96c098518fd6f458266a04"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.20+commit.ba7fbf11.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.20",
"build": "commit.ba7fbf11",
"longVersion": "0.4.25-nightly.2018.6.20+commit.ba7fbf11",
"keccak256": "0x4d54a840997e7357d832ef48fcf254aa73d3cbd98ba2a2db3f4a334343382da7",
"urls": [
"bzzr://1fe442eebadd93850fb579baa2772038a8c9b16c86cbfa41337cccacb1f58f9f"
]
},
{
"path": "soljson-v0.4.25-nightly.2018.6.21+commit.d104718.js",
"version": "0.4.25",
"prerelease": "nightly.2018.6.21",
"build": "commit.d104718",
"longVersion": "0.4.25-nightly.2018.6.21+commit.d104718",
"keccak256": "0x02d92eda9e226921dbc2daa5614718af522b398365698daf38acdac20c49f81a",
"urls": [
"bzzr://0005e5682dd04228df8307d747263acf0c441fcadccceeb48c8174e92783aed2"
]
} }
], ],
"releases": { "releases": {

Loading…
Cancel
Save