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)