diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex index 76a979372b..220426b31f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex @@ -49,6 +49,12 @@ <%= error_tag f, :contract_source_code, id: "contract-source-code-help-block", class: "text-danger", "data-test": "contract-source-code-error" %> +
+ <%= label f, :contructor_arguments, gettext("Enter contructor arguments if the contract had any") %> + <%= textarea f, :constructor_arguments, class: "form-control monospace", rows: 3, "aria-describedby": "contract-constructor-arguments-help-block" %> + <%= error_tag f, :constructor_arguments, id: "contract-constructor-arguments-help-block", class: "text-danger", "data-test": "contract-constructor-arguments-error" %> +
+

<%= gettext "Contract Libraries" %>

diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index ca4cec215f..781c55af15 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -197,7 +197,7 @@ msgid "Blocks Validated" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:119 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:125 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:24 msgid "Cancel" msgstr "" @@ -714,7 +714,7 @@ msgid "Request URL" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:117 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:123 msgid "Reset" msgstr "" @@ -1031,7 +1031,7 @@ msgid "Verify & Publish" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:116 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:122 msgid "Verify & publish" msgstr "" @@ -1172,7 +1172,7 @@ msgid "Loading..." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:114 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:120 msgid "Loading...." msgstr "" @@ -1570,56 +1570,61 @@ msgid "Genesis Block" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:60 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:66 msgid "1 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:55 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:61 msgid "1 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:70 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:76 msgid "2 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:65 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:71 msgid "2 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:80 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:86 msgid "3 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:75 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:81 msgid "3 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:90 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:96 msgid "4 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:85 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:91 msgid "4 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:100 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:106 msgid "5 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:95 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:101 msgid "5 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:52 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:58 msgid "Contract Libraries" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:53 +msgid "Enter contructor arguments if the contract had any" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 009303d05f..62ae365a66 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -197,7 +197,7 @@ msgid "Blocks Validated" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:119 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:125 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:24 msgid "Cancel" msgstr "" @@ -714,7 +714,7 @@ msgid "Request URL" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:117 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:123 msgid "Reset" msgstr "" @@ -1031,7 +1031,7 @@ msgid "Verify & Publish" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:116 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:122 msgid "Verify & publish" msgstr "" @@ -1172,7 +1172,7 @@ msgid "Loading..." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:114 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:120 msgid "Loading...." msgstr "" @@ -1570,56 +1570,61 @@ msgid "Genesis Block" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:60 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:66 msgid "1 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:55 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:61 msgid "1 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:70 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:76 msgid "2 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:65 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:71 msgid "2 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:80 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:86 msgid "3 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:75 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:81 msgid "3 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:90 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:96 msgid "4 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:85 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:91 msgid "4 Library Name" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:100 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:106 msgid "5 Library Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:95 +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:101 msgid "5 Library Name" msgstr "" -#, elixir-format, fuzzy -#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:52 +#, elixir-format +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:58 msgid "Contract Libraries" msgstr "" + +#, elixir-format, fuzzy +#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:53 +msgid "Enter contructor arguments if the contract had any" +msgstr "" diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index ba9c0f613b..ad75980ddf 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1868,6 +1868,35 @@ defmodule Explorer.Chain do |> Data.to_string() end + @doc """ + Fetches contract creation input data. + """ + @spec contract_creation_input_data(String.t()) :: nil | String.t() + def contract_creation_input_data(address_hash) do + query = + from( + address in Address, + where: address.hash == ^address_hash, + preload: [:contracts_creation_internal_transaction, :contracts_creation_transaction] + ) + + transaction = Repo.one(query) + + cond do + is_nil(transaction) -> + "" + + transaction.contracts_creation_internal_transaction && transaction.contracts_creation_internal_transaction.input -> + Data.to_string(transaction.contracts_creation_internal_transaction.input) + + transaction.contracts_creation_transaction && transaction.contracts_creation_transaction.input -> + Data.to_string(transaction.contracts_creation_transaction.input) + + true -> + "" + end + end + @doc """ Inserts a `t:SmartContract.t/0`. diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 7e78c7aa17..e61afea2d4 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -202,6 +202,7 @@ defmodule Explorer.Chain.SmartContract do field(:compiler_version, :string) field(:optimization, :boolean) field(:contract_source_code, :string) + field(:constructor_arguments, :string) field(:abi, {:array, :map}) belongs_to( @@ -217,7 +218,15 @@ defmodule Explorer.Chain.SmartContract do def changeset(%__MODULE__{} = smart_contract, attrs) do smart_contract - |> cast(attrs, [:name, :compiler_version, :optimization, :contract_source_code, :address_hash, :abi]) + |> cast(attrs, [ + :name, + :compiler_version, + :optimization, + :contract_source_code, + :address_hash, + :abi, + :constructor_arguments + ]) |> validate_required([:name, :compiler_version, :optimization, :contract_source_code, :abi, :address_hash]) |> unique_constraint(:address_hash) end @@ -231,6 +240,7 @@ defmodule Explorer.Chain.SmartContract do defp error_message(:compilation), do: "There was an error compiling your contract." defp error_message(:generated_bytecode), do: "Bytecode does not match, please try again." + defp error_message(:constructor_arguments), do: "Constructor arguments do not match, please try again." defp error_message(:name), do: "Wrong contract name, please try again." defp error_message(_), do: "There was an error validating your contract, please try again." end diff --git a/apps/explorer/lib/explorer/smart_contract/publisher.ex b/apps/explorer/lib/explorer/smart_contract/publisher.ex index ef2a986ca2..4cc4d4f0a1 100644 --- a/apps/explorer/lib/explorer/smart_contract/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/publisher.ex @@ -55,12 +55,22 @@ defmodule Explorer.SmartContract.Publisher do end defp attributes(address_hash, params, abi \\ %{}) do + constructor_arguments = params["constructor_arguments"] + + clean_constructor_arguments = + if constructor_arguments != nil && constructor_arguments != "" do + constructor_arguments + else + nil + end + %{ address_hash: address_hash, name: params["name"], compiler_version: params["compiler_version"], optimization: params["optimization"], contract_source_code: params["contract_source_code"], + constructor_arguments: clean_constructor_arguments, abi: abi } end diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 3291c87a68..d7df613f33 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -9,50 +9,47 @@ defmodule Explorer.SmartContract.Verifier do alias Explorer.Chain alias Explorer.SmartContract.Solidity.CodeCompiler + alias Explorer.SmartContract.Verifier.ConstructorArguments def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name} 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, - "compiler_version" => compiler_version, - "external_libraries" => external_libraries - }) do - solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization, external_libraries) - - compare_bytecodes(solc_output, address_hash) - end + def evaluate_authenticity(address_hash, params) do + name = Map.fetch!(params, "name") + contract_source_code = Map.fetch!(params, "contract_source_code") + optimization = Map.fetch!(params, "optimization") + compiler_version = Map.fetch!(params, "compiler_version") + external_libraries = Map.get(params, "external_libraries", %{}) + constructor_arguments = Map.get(params, "constructor_arguments", "") - def evaluate_authenticity(address_hash, %{ - "name" => name, - "contract_source_code" => contract_source_code, - "optimization" => optimization, - "compiler_version" => compiler_version - }) do - solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization) + solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization, external_libraries) - compare_bytecodes(solc_output, address_hash) + compare_bytecodes(solc_output, address_hash, constructor_arguments) end - defp compare_bytecodes({:error, :name}, _), do: {:error, :name} - defp compare_bytecodes({:error, _}, _), do: {:error, :compilation} + 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 + defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash, arguments_data) 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} + blockchain_bytecode_without_whisper = extract_bytecode(blockchain_bytecode) + + cond do + generated_bytecode != blockchain_bytecode_without_whisper -> + {:error, :generated_bytecode} + + !ConstructorArguments.verify(address_hash, blockchain_bytecode, arguments_data) -> + {:error, :constructor_arguments} + + true -> + {:ok, %{abi: abi}} end end diff --git a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex new file mode 100644 index 0000000000..d8b982cc40 --- /dev/null +++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex @@ -0,0 +1,20 @@ +defmodule Explorer.SmartContract.Verifier.ConstructorArguments do + @moduledoc """ + Smart contract contrstructor arguments verification logic. + """ + + alias Explorer.Chain + + def verify(address_hash, bytecode, arguments_data) do + arguments_data = String.replace(arguments_data, "0x", "") + creation_input_data = Chain.contract_creation_input_data(address_hash) + + expected_arguments_data = + creation_input_data + |> String.split(bytecode) + |> List.last() + |> String.replace("0x", "") + + expected_arguments_data == arguments_data + end +end diff --git a/apps/explorer/priv/repo/migrations/20190207105501_add_constructor_arguments_to_smart_contracts.exs b/apps/explorer/priv/repo/migrations/20190207105501_add_constructor_arguments_to_smart_contracts.exs new file mode 100644 index 0000000000..0c71e46d48 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190207105501_add_constructor_arguments_to_smart_contracts.exs @@ -0,0 +1,9 @@ +defmodule Explorer.Repo.Migrations.AddConstructorArgumentsToSmartContracts do + use Ecto.Migration + + def change do + alter table(:smart_contracts) do + add(:constructor_arguments, :string, null: true) + end + end +end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index a02d7c5e26..566eb3ad40 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -3577,4 +3577,58 @@ defmodule Explorer.ChainTest do assert Chain.block_combined_rewards(block) == expected_value end end + + describe "contract_creation_input_data/1" do + test "fetches contract creation input data from contract creation transaction" do + address = insert(:address) + + input = %Data{ + bytes: <<1, 2, 3, 4, 5>> + } + + :transaction + |> insert(created_contract_address_hash: address.hash, input: input) + |> with_block() + + found_creation_data = Chain.contract_creation_input_data(address.hash) + + assert found_creation_data == Data.to_string(input) + end + + test "fetches contract creation input data from internal transaction" do + created_contract_address = insert(:address) + + transaction = + :transaction + |> insert() + |> with_block() + + input = %Data{ + bytes: <<1, 2, 3, 4, 5>> + } + + insert( + :internal_transaction_create, + transaction: transaction, + index: 0, + created_contract_address: created_contract_address, + block_number: transaction.block_number, + transaction_index: transaction.index, + input: input + ) + + assert Chain.contract_creation_input_data(created_contract_address.hash) == Data.to_string(input) + end + + test "can't find address" do + hash = %Hash{ + byte_count: 20, + bytes: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>> + } + + found_creation_data = Chain.contract_creation_input_data(hash) + + assert found_creation_data == "" + end + end end diff --git a/apps/explorer/test/explorer/smart_contract/publisher_test.exs b/apps/explorer/test/explorer/smart_contract/publisher_test.exs index 00641478bd..2807dd3189 100644 --- a/apps/explorer/test/explorer/smart_contract/publisher_test.exs +++ b/apps/explorer/test/explorer/smart_contract/publisher_test.exs @@ -30,9 +30,38 @@ defmodule Explorer.SmartContract.PublisherTest do 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 is_nil(smart_contract.constructor_arguments) assert smart_contract.abi != nil end + test "creates a smart contract with constructor arguments" do + contract_code_info = Factory.contract_code_info() + + contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) + + constructor_arguments = "0102030405" + + params = %{ + "contract_source_code" => contract_code_info.source_code, + "compiler_version" => contract_code_info.version, + "name" => contract_code_info.name, + "optimization" => contract_code_info.optimized, + "constructor_arguments" => constructor_arguments + } + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: contract_code_info.bytecode <> constructor_arguments + ) + |> with_block() + + response = Publisher.publish(contract_address.hash, params) + assert {:ok, %SmartContract{} = smart_contract} = response + + assert smart_contract.constructor_arguments == constructor_arguments + end + test "with invalid data returns error changeset" do address_hash = "" diff --git a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs index 5bd3b24103..b030c900bb 100644 --- a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs +++ b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs @@ -163,9 +163,12 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do end defp remove_init_data_and_whisper_data(code) do - code - |> String.split("0029") - |> List.first() - |> String.split_at(-64) + {res, _} = + code + |> String.split("0029") + |> List.first() + |> String.split_at(-64) + + res end end diff --git a/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs b/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs new file mode 100644 index 0000000000..a9de1e2e5e --- /dev/null +++ b/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs @@ -0,0 +1,44 @@ +defmodule Explorer.SmartContract.Verifier.ConstructorArgumentsTest do + use Explorer.DataCase + + import Explorer.Factory + + alias Explorer.Chain.Data + alias Explorer.SmartContract.Verifier.ConstructorArguments + + describe "verify/3" do + test "verifies constructor arguments" do + bytecode = "0x0102030" + constructor_arguments = "0x405" + address = insert(:address) + + input = %Data{ + bytes: <<1, 2, 3, 4, 5>> + } + + :transaction + |> insert(created_contract_address_hash: address.hash, input: input) + |> with_block() + + assert ConstructorArguments.verify(address.hash, bytecode, constructor_arguments) + end + end + + test "veriies constructor constructor arguments with whisper data" do + bytecode = "0x0102035d943c575be8a2aee2bb7737a765fdd2c6e49b74cd2c92ab0fa8e4282d1a75ae0029" + constructor_arguments = "0x0405" + address = insert(:address) + + input = %Data{ + bytes: + <<1, 2, 3, 93, 148, 60, 87, 91, 232, 162, 174, 226, 187, 119, 55, 167, 101, 253, 210, 198, 228, 155, 116, 205, + 44, 146, 171, 15, 168, 228, 40, 45, 26, 117, 174, 0, 41, 4, 5>> + } + + :transaction + |> insert(created_contract_address_hash: address.hash, input: input) + |> with_block() + + assert ConstructorArguments.verify(address.hash, bytecode, constructor_arguments) + end +end diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 7d5a14be0e..584bb568ef 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -56,6 +56,57 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end + test "verifies smart contract with constructor arguments", %{ + contract_code_info: contract_code_info + } do + contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) + + constructor_arguments = "0102030405" + + params = %{ + "contract_source_code" => contract_code_info.source_code, + "compiler_version" => contract_code_info.version, + "name" => contract_code_info.name, + "optimization" => contract_code_info.optimized, + "constructor_arguments" => constructor_arguments + } + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: contract_code_info.bytecode <> constructor_arguments + ) + |> with_block() + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "returns error when constructor arguments do not match", %{ + contract_code_info: contract_code_info + } do + contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) + + constructor_arguments = "0102030405" + + params = %{ + "contract_source_code" => contract_code_info.source_code, + "compiler_version" => contract_code_info.version, + "name" => contract_code_info.name, + "optimization" => contract_code_info.optimized, + "constructor_arguments" => constructor_arguments + } + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: Verifier.extract_bytecode(contract_code_info.bytecode) <> "010203" + ) + |> with_block() + + assert {:error, :constructor_arguments} = Verifier.evaluate_authenticity(contract_address.hash, params) + end + 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)