Support multiple compile versions

This will allow that the versions selected in the page have
real impact on how the Contract will be verified.
pull/288/head
Igor Florian 7 years ago
parent 2ebd5eaf57
commit 44430af6f9
  1. 122
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  2. 8
      apps/explorer/lib/explorer/smart_contract/solidity/compiler_version.ex
  3. 14
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  4. 3
      apps/explorer/priv/compile_solc.js
  5. 40
      apps/explorer/test/explorer/smart_contract/publisher_test.exs
  6. 123
      apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
  7. 2
      apps/explorer/test/explorer/smart_contract/solidity/compiler_version_test.exs
  8. 85
      apps/explorer/test/explorer/smart_contract/verifier_test.exs
  9. 32
      apps/explorer/test/support/factory.ex
  10. 47
      apps/explorer_web/test/explorer_web/features/address_contract_verification_test.exs

@ -3,14 +3,36 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
Module responsible to compile the Solidity code of a given Smart Contract.
"""
@doc ~S"""
@doc """
Compiles a code in the solidity command line.
Returns a `Map`.
## 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)
{:ok, %{
iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run(
...> "SimpleStorage",
...> "v0.4.24+commit.e67f0147",
...> \"""
...> pragma solidity ^0.4.24;
...>
...> contract SimpleStorage {
...> uint storedData;
...>
...> function set(uint x) public {
...> storedData = x;
...> }
...>
...> function get() public constant returns (uint) {
...> return storedData;
...> }
...> }
...> \""",
...> false
...> )
{
:ok,
%{
"abi" => [
%{
"constant" => false,
@ -31,66 +53,66 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
"type" => "function"
}
],
"bytecode" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029",
"name" => "SimpleStorage"
}}
"bytecode" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820235fceab083d33bf112b473c85551306a29f32dcdc7e95b4dfdd697c1db188ec0029",
"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} =
System.cmd(
"node",
[
Application.app_dir(:explorer, "priv/compile_solc.js"),
generate_settings(name, code, optimization),
"v0.4.24+commit.e67f0147"
code,
compiler_version,
optimize_value(optimize)
]
)
case Jason.decode!(response) do
%{
"contracts" => %{
^name => %{
^name => %{
"abi" => abi,
"evm" => %{
"bytecode" => %{"object" => bytecode}
}
}
}
with %{"contracts" => contracts} <- Jason.decode!(response),
%{"interface" => abi, "runtimeBytecode" => bytecode, "opcodes" => opcodes} <-
get_contract_info(contracts, name) do
{
:ok,
%{
"abi" => Jason.decode!(abi),
"bytecode" => bytecode,
"name" => name,
"opcodes" => opcodes
}
} ->
{:ok, %{"abi" => abi, "bytecode" => bytecode, "name" => name}}
}
else
error ->
parse_error(error)
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, :compilation}
{:error, :name}
end
end
@doc """
For more output options check the documentation.
https://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html#compiler-input-and-output-json-description
"""
def generate_settings(name, code, optimization) do
"""
{
"language": "Solidity",
"sources": {
"#{name}":
{
"content": "#{code}"
}
},
"settings": {
"optimizer": {
"enabled": #{optimization}
},
"outputSelection": {
"*": {
"*": [ "evm.bytecode", "evm.deployedBytecode", "evm.gasEstimates", "abi", "metadata" ]
}
}
}
}
"""
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

@ -30,11 +30,17 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersion do
releases
|> Map.to_list()
|> Enum.map(fn {key, _value} -> {key, key} end)
|> Enum.map(fn {key, value} -> {key, extract_version(value)} end)
|> Enum.sort()
|> Enum.reverse()
end
defp extract_version(version) do
version
|> String.replace_prefix("soljson-", "")
|> String.replace_suffix(".js", "")
end
defp decode_json(json) do
Jason.decode!(json)
end

@ -11,18 +11,24 @@ defmodule Explorer.SmartContract.Verifier do
alias Explorer.SmartContract.Solidity.CodeCompiler
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, %{
"name" => name,
"contract_source_code" => contract_source_code,
"optimization" => optimization
"optimization" => optimization,
"compiler" => compiler_version
}) 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(compilation_error = {:error, _}, _), do: compilation_error
defp compare_bytecodes({:error, :name}, _), do: {:error, :name}
defp compare_bytecodes({:error, _}, _), do: {:error, :compilation}
defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash) do
generated_bytecode = extract_bytecode(bytecode)

@ -4,11 +4,12 @@ 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(solcSnapshot.compileStandardWrapper(sourceCode));
console.log(JSON.stringify(solcSnapshot.compile(sourceCode, optimize)));
}
});

@ -5,43 +5,29 @@ defmodule Explorer.SmartContract.PublisherTest do
doctest Explorer.SmartContract.Publisher
alias Explorer.Chain.{SmartContract, Hash}
alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.Publisher
alias Explorer.Factory
describe "publish/2" do
test "with valid data creates a smart_contract" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c"
contract_code_info = Factory.contract_code_info()
smart_contract_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
)
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
valid_attrs = %{
"contract_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" => "0.4.24",
"name" => "SimpleStorage",
"optimization" => false
"contract_source_code" => contract_code_info.source_code,
"compiler_version" => contract_code_info.version,
"name" => contract_code_info.name,
"optimization" => contract_code_info.optimized
}
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 Hash.to_string(smart_contract.address_hash) == address_hash
assert smart_contract.compiler_version == valid_attrs["compiler"]
assert smart_contract.compiler_version == valid_attrs["compiler_version"]
assert smart_contract.optimization == valid_attrs["optimization"]
assert smart_contract.contract_source_code == valid_attrs["contract_source_code"]
assert smart_contract.abi != nil

@ -4,15 +4,56 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
doctest Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.Factory
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"
optimization = false
code = """
pragma solidity ^0.4.24;
contract SimpleStorage {
uint storedData;
@ -26,42 +67,74 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
}
"""
response = CodeCompiler.run(name, code, optimization)
version = "v0.1.3-nightly.2015.9.25+commit.4457170"
response = CodeCompiler.run(name, version, code, optimize)
assert {:ok,
%{
"abi" => _,
"bytecode" => _,
"name" => _
"name" => _,
"opcodes" => _
}} = response
end
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
describe "generate_settings/2" do
test "creates a json file with the solidity compiler expected settings" do
name = "SimpleStorage"
optimization = false
describe "get_contract_info/1" do
test "return name error when the Contract name doesn't match" do
name = "Name"
different_name = "diff_name"
code = """
pragma solidity ^0.4.24;
response = CodeCompiler.get_contract_info(%{name => %{}}, different_name)
contract SimpleStorage {
uint storedData;
assert {:error, :name} == response
end
function set(uint x) public {
storedData = x;
}
test "returns an empty list of errors for empty info" do
name = "Name"
function get() public constant returns (uint) {
return storedData;
}
}
"""
response = CodeCompiler.get_contract_info(%{}, name)
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 String.contains?(generated, "settings") == true
assert contract_inner_info == response
end
end
end

@ -24,7 +24,7 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersionTest do
end)
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 == {"0.4.9", "v0.4.9+commit.364da425"} end) == true
end
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
alias Explorer.SmartContract.Verifier
alias Explorer.Factory
describe "evaluate_authenticity/2" do
test "verifies the generated bytecode against bytecode retrieved from the blockchain" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c"
smart_contract_bytecode =
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
setup do
{:ok, contract_code_info: Factory.contract_code_info()}
end
insert(
:internal_transaction_create,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
test "verifies the generated bytecode against bytecode retrieved from the blockchain", %{
contract_code_info: contract_code_info
} do
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
params = %{
"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; } }",
"compiler" => "0.4.24",
"name" => "SimpleStorage",
"optimization" => false
"contract_source_code" => contract_code_info.source_code,
"compiler_version" => contract_code_info.version,
"name" => contract_code_info.name,
"optimization" => contract_code_info.optimized
}
assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(address_hash, params)
assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
assert abi != nil
end
test "returns error when bytecoed doesn't match" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c"
test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
wrong_smart_contract_bytecode =
"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
)
different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}"
params = %{
"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; } }",
"compiler" => "0.4.24",
"name" => "SimpleStorage",
"optimization" => false
"contract_source_code" => different_code,
"compiler_version" => contract_code_info.version,
"name" => contract_code_info.name,
"optimization" => contract_code_info.optimized
}
assert {:error, :generated_bytecode} = Verifier.evaluate_authenticity(address_hash, params)
response = Verifier.evaluate_authenticity(contract_address.hash, params)
assert {:error, :generated_bytecode} = response
end
test "returns error when there is a compilation problem" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c"
test "returns error when there is a compilation problem", %{contract_code_info: contract_code_info} do
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
params = %{
"contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { ",
"compiler" => "0.4.24",
"name" => "SimpleStorage",
"optimization" => false
"compiler_version" => contract_code_info.version,
"name" => contract_code_info.name,
"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

@ -29,6 +29,38 @@ defmodule Explorer.Factory do
}
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
{:ok, address_hash} =
"address_hash"

@ -4,6 +4,7 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
import Wallaby.Query
alias Plug.Conn
alias Explorer.Factory
setup do
bypass = Bypass.open()
@ -16,51 +17,19 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
test "users validates smart contract", %{session: session, bypass: bypass} do
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 =
"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;
}
}
"""
contract_address = insert(:contract_address, contract_code: bytecode)
session
|> visit("/en/addresses/#{address_hash}/contract_verifications/new")
|> fill_in(text_field("Contract Name"), with: "SimpleStorage")
|> click(option("0.4.24"))
|> visit("/en/addresses/#{contract_address.hash}/contract_verifications/new")
|> fill_in(text_field("Contract Name"), with: name)
|> click(option(version))
|> 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"))
assert current_path(session) =~ ~r/\/en\/addresses\/#{address_hash}\/contracts/
assert current_path(session) =~ ~r/\/en\/addresses\/#{contract_address.hash}\/contracts/
end
test "with invalid data shows error messages", %{session: session, bypass: bypass} do

Loading…
Cancel
Save