|
|
|
@ -10,7 +10,6 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
alias Explorer.Chain |
|
|
|
|
alias Explorer.Chain.{Hash, SmartContract} |
|
|
|
|
alias Explorer.SmartContract.Helper |
|
|
|
|
require Logger |
|
|
|
|
|
|
|
|
|
@typedoc """ |
|
|
|
|
Map of functions to call with the values for the function to be called with. |
|
|
|
@ -61,24 +60,35 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
) |
|
|
|
|
# => %{"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()) :: |
|
|
|
|
functions_results() |
|
|
|
|
def query_verified_contract(address_hash, functions, from, mabi) do |
|
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, from) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@spec query_verified_contract(Hash.Address.t(), functions(), SmartContract.abi() | nil) :: functions_results() |
|
|
|
|
def query_verified_contract(address_hash, functions, mabi \\ nil) do |
|
|
|
|
query_verified_contract_inner(address_hash, functions, mabi, nil) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@spec query_verified_contract_inner(Hash.Address.t(), functions(), SmartContract.abi() | nil, String.t() | nil) :: |
|
|
|
|
functions_results() |
|
|
|
|
defp query_verified_contract_inner(address_hash, functions, mabi, from) do |
|
|
|
|
contract_address = Hash.to_string(address_hash) |
|
|
|
|
|
|
|
|
|
abi = |
|
|
|
|
case mabi do |
|
|
|
|
nil -> |
|
|
|
|
address_hash |
|
|
|
|
|> Chain.address_hash_to_smart_contract() |
|
|
|
|
|> Map.get(:abi) |
|
|
|
|
abi = prepare_abi(mabi, address_hash) |
|
|
|
|
|
|
|
|
|
_ -> |
|
|
|
|
mabi |
|
|
|
|
end |
|
|
|
|
query_contract(contract_address, from, abi, functions) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
query_contract(contract_address, abi, functions) |
|
|
|
|
defp prepare_abi(nil, address_hash) do |
|
|
|
|
address_hash |
|
|
|
|
|> Chain.address_hash_to_smart_contract() |
|
|
|
|
|> Map.get(:abi) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
defp prepare_abi(mabi, _address_hash), do: mabi |
|
|
|
|
|
|
|
|
|
@doc """ |
|
|
|
|
Runs contract functions on a given address for smart contract with an expected ABI and functions. |
|
|
|
|
|
|
|
|
@ -101,7 +111,7 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
|
|
|
|
|
@spec query_contract( |
|
|
|
|
String.t(), |
|
|
|
|
String.t(), |
|
|
|
|
String.t() | nil, |
|
|
|
|
term(), |
|
|
|
|
functions() |
|
|
|
|
) :: functions_results() |
|
|
|
@ -358,6 +368,12 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
%{output: outputs, names: names} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name) |
|
|
|
|
%{output: outputs, names: names} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@doc """ |
|
|
|
|
Fetches the blockchain value of a function that requires arguments. |
|
|
|
|
""" |
|
|
|
@ -368,30 +384,45 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
|
|
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom()) :: [%{}] |
|
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type) do |
|
|
|
|
query_function_inner(contract_address_hash, method_id, args, type, nil) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), String.t() | nil) :: [%{}] |
|
|
|
|
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, from) do |
|
|
|
|
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, from) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), String.t() | nil) :: [%{}] |
|
|
|
|
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) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
@spec query_function_inner(Hash.t(), String.t(), [term()], atom(), String.t() | nil) :: [%{}] |
|
|
|
|
defp query_function_inner(contract_address_hash, method_id, args, type, from) do |
|
|
|
|
abi = get_abi(contract_address_hash, type) |
|
|
|
|
|
|
|
|
|
parsed_final_abi = |
|
|
|
|
abi |
|
|
|
|
|> ABI.parse_specification() |
|
|
|
|
|
|
|
|
|
%{outputs: outputs, method_id: method_id} = |
|
|
|
|
case parsed_final_abi do |
|
|
|
|
nil -> |
|
|
|
|
nil |
|
|
|
|
%{outputs: outputs, method_id: method_id} = proccess_abi(parsed_final_abi, method_id) |
|
|
|
|
|
|
|
|
|
_ -> |
|
|
|
|
Logger.debug(Kernel.inspect(parsed_final_abi)) |
|
|
|
|
function_object = find_function_by_method(parsed_final_abi, method_id) |
|
|
|
|
query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
%ABI.FunctionSelector{returns: returns, method_id: method_id} = function_object |
|
|
|
|
defp proccess_abi(nil, _method_id), do: nil |
|
|
|
|
|
|
|
|
|
outputs = extract_outputs(returns) |
|
|
|
|
defp proccess_abi(abi, method_id) do |
|
|
|
|
function_object = find_function_by_method(abi, method_id) |
|
|
|
|
%ABI.FunctionSelector{returns: returns, method_id: method_id} = function_object |
|
|
|
|
outputs = extract_outputs(returns) |
|
|
|
|
|
|
|
|
|
%{outputs: outputs, method_id: method_id} |
|
|
|
|
end |
|
|
|
|
%{outputs: outputs, method_id: method_id} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
defp query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id) do |
|
|
|
|
contract_address_hash |
|
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, abi) |
|
|
|
|
|> query_verified_contract(%{method_id => normalize_args(args)}, from, abi) |
|
|
|
|
|> link_outputs_and_values(outputs, method_id) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
@ -432,11 +463,8 @@ defmodule Explorer.SmartContract.Reader do |
|
|
|
|
defp validate_name(name), do: not is_nil(name) and String.length(name) > 0 |
|
|
|
|
|
|
|
|
|
defp find_function_by_method(parsed_abi, method_id) do |
|
|
|
|
Logger.debug("find fucntion") |
|
|
|
|
Logger.debug(method_id) |
|
|
|
|
parsed_abi |
|
|
|
|
|> Enum.filter(fn %ABI.FunctionSelector{method_id: find_method_id} -> |
|
|
|
|
Logger.debug(Kernel.inspect(Base.encode16(find_method_id, case: :lower))) |
|
|
|
|
if find_method_id do |
|
|
|
|
Base.encode16(find_method_id, case: :lower) == method_id || find_method_id == method_id |
|
|
|
|
else |
|
|
|
|