|
|
|
@ -5,7 +5,7 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do |
|
|
|
|
alias ABI.{FunctionSelector, TypeDecoder} |
|
|
|
|
alias Explorer.Chain |
|
|
|
|
|
|
|
|
|
def verify(address_hash, contract_code, arguments_data) do |
|
|
|
|
def verify(address_hash, contract_code, arguments_data, contract_source_code) do |
|
|
|
|
arguments_data = arguments_data |> String.trim_trailing() |> String.trim_leading("0x") |
|
|
|
|
|
|
|
|
|
creation_code = |
|
|
|
@ -18,7 +18,7 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do |
|
|
|
|
if verify_older_version(creation_code, contract_code, check_func) do |
|
|
|
|
true |
|
|
|
|
else |
|
|
|
|
extract_constructor_arguments(creation_code, check_func) |
|
|
|
|
extract_constructor_arguments(creation_code, check_func, contract_source_code) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
@ -31,22 +31,22 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do |
|
|
|
|
|> check_func.() |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
defp extract_constructor_arguments(code, check_func) do |
|
|
|
|
defp extract_constructor_arguments(code, check_func, contract_source_code) do |
|
|
|
|
case code do |
|
|
|
|
# Solidity ~ 4.23 # https://solidity.readthedocs.io/en/v0.4.23/metadata.html |
|
|
|
|
"a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> constructor_arguments -> |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func) |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code) |
|
|
|
|
|
|
|
|
|
# Solidity >= 0.5.10 https://solidity.readthedocs.io/en/v0.5.10/metadata.html |
|
|
|
|
"a265627a7a72305820" <> |
|
|
|
|
<<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func) |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code) |
|
|
|
|
|
|
|
|
|
# Solidity >= 0.5.11 https://github.com/ethereum/solidity/blob/develop/Changelog.md#0511-2019-08-12 |
|
|
|
|
# Metadata: Update the swarm hash to the current specification, changes bzzr0 to bzzr1 and urls to use bzz-raw:// |
|
|
|
|
"a265627a7a72315820" <> |
|
|
|
|
<<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func) |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code) |
|
|
|
|
|
|
|
|
|
# Solidity >= 0.6.0 https://github.com/ethereum/solidity/blob/develop/Changelog.md#060-2019-12-17 |
|
|
|
|
# https://github.com/ethereum/solidity/blob/26b700771e9cc9c956f0503a05de69a1be427963/docs/metadata.rst#encoding-of-the-metadata-hash-in-the-bytecode |
|
|
|
@ -60,27 +60,47 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do |
|
|
|
|
# Fixing PR has been created https://github.com/ethereum/solidity/pull/8174 |
|
|
|
|
"a264697066735822" <> |
|
|
|
|
<<_::binary-size(68)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0033" <> constructor_arguments -> |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func) |
|
|
|
|
extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code) |
|
|
|
|
|
|
|
|
|
<<>> -> |
|
|
|
|
check_func.("") |
|
|
|
|
|
|
|
|
|
<<_::binary-size(2)>> <> rest -> |
|
|
|
|
extract_constructor_arguments(rest, check_func) |
|
|
|
|
extract_constructor_arguments(rest, check_func, contract_source_code) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
defp extract_constructor_arguments_check_func(constructor_arguments, check_func) do |
|
|
|
|
defp extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code) do |
|
|
|
|
constructor_arguments = |
|
|
|
|
remove_require_messages_from_constructor_arguments(contract_source_code, constructor_arguments) |
|
|
|
|
|
|
|
|
|
check_func_result = check_func.(constructor_arguments) |
|
|
|
|
|
|
|
|
|
if check_func_result do |
|
|
|
|
check_func_result |
|
|
|
|
else |
|
|
|
|
extract_constructor_arguments(constructor_arguments, check_func) |
|
|
|
|
extract_constructor_arguments(constructor_arguments, check_func, contract_source_code) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def remove_require_messages_from_constructor_arguments(contract_source_code, constructor_arguments) do |
|
|
|
|
msgs_list = |
|
|
|
|
contract_source_code |
|
|
|
|
|> extract_require_messages_from_constructor() |
|
|
|
|
|> Enum.reverse() |
|
|
|
|
|
|
|
|
|
Enum.reduce(msgs_list, constructor_arguments, fn msg, pure_constructor_arguments -> |
|
|
|
|
case String.split(pure_constructor_arguments, msg, parts: 2) do |
|
|
|
|
[_, constructor_arguments_part] -> |
|
|
|
|
constructor_arguments_part |
|
|
|
|
|
|
|
|
|
[_] -> |
|
|
|
|
pure_constructor_arguments |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def find_constructor_arguments(address_hash, abi) do |
|
|
|
|
def find_constructor_arguments(address_hash, abi, contract_source_code) do |
|
|
|
|
creation_code = |
|
|
|
|
address_hash |
|
|
|
|
|> Chain.contract_creation_input_data() |
|
|
|
@ -103,6 +123,61 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
extract_constructor_arguments(creation_code, check_func) |
|
|
|
|
extract_constructor_arguments(creation_code, check_func, contract_source_code) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def extract_require_messages_from_constructor(contract_source_code) do |
|
|
|
|
constructor = find_constructor_content(contract_source_code) |
|
|
|
|
require_contents = find_require_in_constructor(constructor) |
|
|
|
|
|
|
|
|
|
messages_list = |
|
|
|
|
Enum.reduce(require_contents, [], fn require_content, msgs -> |
|
|
|
|
msg = get_require_message_hex(require_content) |
|
|
|
|
if msg, do: [msg | msgs] |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
if messages_list, do: messages_list, else: [] |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def find_constructor_content(contract_source_code) do |
|
|
|
|
case String.split(contract_source_code, "constructor", parts: 2) do |
|
|
|
|
[_, right_from_contstructor] -> |
|
|
|
|
[_, right_from_contstructor_inside] = String.split(right_from_contstructor, "{", parts: 2) |
|
|
|
|
[constructor, _] = String.split(right_from_contstructor_inside, "}", parts: 2) |
|
|
|
|
constructor |
|
|
|
|
|
|
|
|
|
[_] -> |
|
|
|
|
nil |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def find_require_in_constructor(constructor) do |
|
|
|
|
if constructor do |
|
|
|
|
[_ | requires] = String.split(constructor, "require") |
|
|
|
|
|
|
|
|
|
Enum.reduce(requires, [], fn right_from_require, requires_list -> |
|
|
|
|
[_ | [right_from_require_inside]] = String.split(right_from_require, "(", parts: 2) |
|
|
|
|
[require_content | _] = String.split(right_from_require_inside, ");", parts: 2) |
|
|
|
|
[require_content | requires_list] |
|
|
|
|
end) |
|
|
|
|
else |
|
|
|
|
[] |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def get_require_message_hex(require_content) do |
|
|
|
|
case String.split(require_content, ",", parts: 2) do |
|
|
|
|
[_ | [msg]] -> |
|
|
|
|
msg |
|
|
|
|
|> String.trim() |
|
|
|
|
|> String.trim_leading("\"") |
|
|
|
|
|> String.trim_trailing("\"") |
|
|
|
|
|> String.trim_leading("'") |
|
|
|
|
|> String.trim_trailing("'") |
|
|
|
|
|> Base.encode16(case: :lower) |
|
|
|
|
|
|
|
|
|
[_] -> |
|
|
|
|
nil |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|