|
|
@ -60,25 +60,32 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
) |
|
|
|
) |
|
|
|
# => %{"sum" => {:error, "Data overflow encoding int, data `abc` cannot fit in 256 bits"}} |
|
|
|
# => %{"sum" => {:error, "Data overflow encoding int, data `abc` cannot fit in 256 bits"}} |
|
|
|
""" |
|
|
|
""" |
|
|
|
@spec query_verified_contract(Hash.Address.t(), functions(), String.t() | nil, SmartContract.abi()) :: |
|
|
|
@spec query_verified_contract(Hash.Address.t(), functions(), String.t() | nil, true | false, SmartContract.abi()) :: |
|
|
|
functions_results() |
|
|
|
functions_results() |
|
|
|
def query_verified_contract(address_hash, functions, from, mabi) do |
|
|
|
def query_verified_contract(address_hash, functions, from, leave_error_as_map, mabi) do |
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, from) |
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, from, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_verified_contract(Hash.Address.t(), functions(), SmartContract.abi() | nil) :: functions_results() |
|
|
|
@spec query_verified_contract(Hash.Address.t(), functions(), true | false, SmartContract.abi() | nil) :: |
|
|
|
def query_verified_contract(address_hash, functions, mabi \\ nil) do |
|
|
|
functions_results() |
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, nil) |
|
|
|
def query_verified_contract(address_hash, functions, leave_error_as_map, mabi \\ nil) do |
|
|
|
|
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, nil, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_verified_contract_inner(Hash.Address.t(), functions(), SmartContract.abi() | nil, String.t() | nil) :: |
|
|
|
@spec query_verified_contract_inner( |
|
|
|
|
|
|
|
Hash.Address.t(), |
|
|
|
|
|
|
|
functions(), |
|
|
|
|
|
|
|
SmartContract.abi() | nil, |
|
|
|
|
|
|
|
String.t() | nil, |
|
|
|
|
|
|
|
true | false |
|
|
|
|
|
|
|
) :: |
|
|
|
functions_results() |
|
|
|
functions_results() |
|
|
|
defp query_verified_contract_inner(address_hash, functions, mabi, from) do |
|
|
|
defp query_verified_contract_inner(address_hash, functions, mabi, from, leave_error_as_map) do |
|
|
|
contract_address = Hash.to_string(address_hash) |
|
|
|
contract_address = Hash.to_string(address_hash) |
|
|
|
|
|
|
|
|
|
|
|
abi = prepare_abi(mabi, address_hash) |
|
|
|
abi = prepare_abi(mabi, address_hash) |
|
|
|
|
|
|
|
|
|
|
|
query_contract(contract_address, from, abi, functions) |
|
|
|
query_contract(contract_address, from, abi, functions, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
defp prepare_abi(nil, address_hash) do |
|
|
|
defp prepare_abi(nil, address_hash) do |
|
|
@ -103,20 +110,22 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
@spec query_contract( |
|
|
|
@spec query_contract( |
|
|
|
String.t(), |
|
|
|
String.t(), |
|
|
|
term(), |
|
|
|
term(), |
|
|
|
functions() |
|
|
|
functions(), |
|
|
|
|
|
|
|
true | false |
|
|
|
) :: functions_results() |
|
|
|
) :: functions_results() |
|
|
|
def query_contract(contract_address, abi, functions) do |
|
|
|
def query_contract(contract_address, abi, functions, leave_error_as_map) do |
|
|
|
query_contract_inner(contract_address, abi, functions, nil, nil, false) |
|
|
|
query_contract_inner(contract_address, abi, functions, nil, nil, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_contract( |
|
|
|
@spec query_contract( |
|
|
|
String.t(), |
|
|
|
String.t(), |
|
|
|
String.t() | nil, |
|
|
|
String.t() | nil, |
|
|
|
term(), |
|
|
|
term(), |
|
|
|
functions() |
|
|
|
functions(), |
|
|
|
|
|
|
|
true | false |
|
|
|
) :: functions_results() |
|
|
|
) :: functions_results() |
|
|
|
def query_contract(contract_address, from, abi, functions) do |
|
|
|
def query_contract(contract_address, from, abi, functions, leave_error_as_map) do |
|
|
|
query_contract_inner(contract_address, abi, functions, nil, from, true) |
|
|
|
query_contract_inner(contract_address, abi, functions, nil, from, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_contract_by_block_number( |
|
|
|
@spec query_contract_by_block_number( |
|
|
@ -223,7 +232,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
|
|
|
|
|
|
|
abi_with_method_id |
|
|
|
abi_with_method_id |
|
|
|
|> Enum.filter(&Helper.queriable_method?(&1)) |
|
|
|
|> Enum.filter(&Helper.queriable_method?(&1)) |
|
|
|
|> Enum.map(&fetch_current_value_from_blockchain(&1, abi_with_method_id, contract_address_hash)) |
|
|
|
|> Enum.map(&fetch_current_value_from_blockchain(&1, abi_with_method_id, contract_address_hash, false)) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -239,7 +248,9 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
|
|
|
|
|
|
|
implementation_abi_with_method_id |
|
|
|
implementation_abi_with_method_id |
|
|
|
|> Enum.filter(&Helper.queriable_method?(&1)) |
|
|
|
|> Enum.filter(&Helper.queriable_method?(&1)) |
|
|
|
|> Enum.map(&fetch_current_value_from_blockchain(&1, implementation_abi_with_method_id, contract_address_hash)) |
|
|
|
|> Enum.map( |
|
|
|
|
|
|
|
&fetch_current_value_from_blockchain(&1, implementation_abi_with_method_id, contract_address_hash, false) |
|
|
|
|
|
|
|
) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -357,7 +368,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
"tuple[#{tuple_types}]" |
|
|
|
"tuple[#{tuple_types}]" |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def fetch_current_value_from_blockchain(function, abi, contract_address_hash) do |
|
|
|
def fetch_current_value_from_blockchain(function, abi, contract_address_hash, leave_error_as_map) do |
|
|
|
values = |
|
|
|
values = |
|
|
|
case function do |
|
|
|
case function do |
|
|
|
%{"inputs" => []} -> |
|
|
|
%{"inputs" => []} -> |
|
|
@ -366,7 +377,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
outputs = function["outputs"] |
|
|
|
outputs = function["outputs"] |
|
|
|
|
|
|
|
|
|
|
|
contract_address_hash |
|
|
|
contract_address_hash |
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, abi) |
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, leave_error_as_map, abi) |
|
|
|
|> link_outputs_and_values(outputs, method_id) |
|
|
|
|> link_outputs_and_values(outputs, method_id) |
|
|
|
|
|
|
|
|
|
|
|
_ -> |
|
|
|
_ -> |
|
|
@ -379,13 +390,14 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
@doc """ |
|
|
|
@doc """ |
|
|
|
Method performs query of read functions of a smart contract. |
|
|
|
Method performs query of read functions of a smart contract. |
|
|
|
`type` could be :proxy or :reqular |
|
|
|
`type` could be :proxy or :reqular |
|
|
|
|
|
|
|
if ethereumJSONRPC will return some errors it will represented as map |
|
|
|
""" |
|
|
|
""" |
|
|
|
@spec query_function_with_names(Hash.t(), %{method_id: String.t(), args: [term()] | nil}, atom(), String.t()) :: %{ |
|
|
|
@spec query_function_with_names(Hash.t(), %{method_id: String.t(), args: [term()] | nil}, atom(), String.t()) :: %{ |
|
|
|
:names => [any()], |
|
|
|
:names => [any()], |
|
|
|
:output => [%{}] |
|
|
|
:output => [%{}] |
|
|
|
} |
|
|
|
} |
|
|
|
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name) do |
|
|
|
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name) do |
|
|
|
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type) |
|
|
|
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, true) |
|
|
|
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name) |
|
|
|
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name) |
|
|
|
%{output: outputs, names: names} |
|
|
|
%{output: outputs, names: names} |
|
|
|
end |
|
|
|
end |
|
|
@ -403,7 +415,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
String.t() |
|
|
|
String.t() |
|
|
|
) :: %{:names => [any()], :output => [%{}]} |
|
|
|
) :: %{:names => [any()], :output => [%{}]} |
|
|
|
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name, from) do |
|
|
|
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name, from) do |
|
|
|
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from) |
|
|
|
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from, true) |
|
|
|
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name) |
|
|
|
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name) |
|
|
|
%{output: outputs, names: names} |
|
|
|
%{output: outputs, names: names} |
|
|
|
end |
|
|
|
end |
|
|
@ -411,28 +423,30 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
@doc """ |
|
|
|
@doc """ |
|
|
|
Fetches the blockchain value of a function that requires arguments. |
|
|
|
Fetches the blockchain value of a function that requires arguments. |
|
|
|
""" |
|
|
|
""" |
|
|
|
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom()) :: [%{}] |
|
|
|
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), true | false) :: [%{}] |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type) do |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, leave_error_as_map) do |
|
|
|
query_function(contract_address_hash, %{method_id: method_id, args: []}, type) |
|
|
|
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom()) :: [%{}] |
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), true | false) :: [%{}] |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type) do |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, leave_error_as_map) do |
|
|
|
query_function_inner(contract_address_hash, method_id, args, type, nil) |
|
|
|
query_function_inner(contract_address_hash, method_id, args, type, nil, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), String.t() | nil) :: [%{}] |
|
|
|
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), String.t() | nil, true | false) :: [%{}] |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, from) do |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, from, leave_error_as_map) do |
|
|
|
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, from) |
|
|
|
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, from, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), String.t() | nil) :: [%{}] |
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), String.t() | nil, true | false) :: [ |
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from) do |
|
|
|
%{} |
|
|
|
query_function_inner(contract_address_hash, method_id, args, type, from) |
|
|
|
] |
|
|
|
|
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from, leave_error_as_map) do |
|
|
|
|
|
|
|
query_function_inner(contract_address_hash, method_id, args, type, from, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@spec query_function_inner(Hash.t(), String.t(), [term()], atom(), String.t() | nil) :: [%{}] |
|
|
|
@spec query_function_inner(Hash.t(), String.t(), [term()], atom(), String.t() | nil, true | false) :: [%{}] |
|
|
|
defp query_function_inner(contract_address_hash, method_id, args, type, from) do |
|
|
|
defp query_function_inner(contract_address_hash, method_id, args, type, from, leave_error_as_map) do |
|
|
|
abi = get_abi(contract_address_hash, type) |
|
|
|
abi = get_abi(contract_address_hash, type) |
|
|
|
|
|
|
|
|
|
|
|
parsed_final_abi = |
|
|
|
parsed_final_abi = |
|
|
@ -441,7 +455,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
|
|
|
|
|
|
|
%{outputs: outputs, method_id: method_id} = proccess_abi(parsed_final_abi, method_id) |
|
|
|
%{outputs: outputs, method_id: method_id} = proccess_abi(parsed_final_abi, method_id) |
|
|
|
|
|
|
|
|
|
|
|
query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id) |
|
|
|
query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id, leave_error_as_map) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
defp proccess_abi(nil, _method_id), do: nil |
|
|
|
defp proccess_abi(nil, _method_id), do: nil |
|
|
@ -454,9 +468,9 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
%{outputs: outputs, method_id: method_id} |
|
|
|
%{outputs: outputs, method_id: method_id} |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
defp query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id) do |
|
|
|
defp query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id, leave_error_as_map) do |
|
|
|
contract_address_hash |
|
|
|
contract_address_hash |
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, from, abi) |
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, from, leave_error_as_map, abi) |
|
|
|
|> link_outputs_and_values(outputs, method_id) |
|
|
|
|> link_outputs_and_values(outputs, method_id) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|