|
|
|
@ -1,8 +1,7 @@ |
|
|
|
|
defmodule ExW3 do |
|
|
|
|
|
|
|
|
|
@spec bytes_to_string(binary()) :: binary() |
|
|
|
|
@doc "converts Ethereum style bytes to string" |
|
|
|
|
def bytes_to_string bytes do |
|
|
|
|
def bytes_to_string(bytes) do |
|
|
|
|
bytes |
|
|
|
|
|> Base.encode16(case: :lower) |
|
|
|
|
|> String.replace_trailing("0", "") |
|
|
|
@ -64,7 +63,10 @@ defmodule ExW3 do |
|
|
|
|
def tx_receipt(tx_hash) do |
|
|
|
|
case Ethereumex.HttpClient.eth_get_transaction_receipt(tx_hash) do |
|
|
|
|
{:ok, receipt} -> |
|
|
|
|
Map.merge receipt, keys_to_decimal(receipt, ["blockNumber", "cumulativeGasUsed", "gasUsed"]) |
|
|
|
|
Map.merge( |
|
|
|
|
receipt, |
|
|
|
|
keys_to_decimal(receipt, ["blockNumber", "cumulativeGasUsed", "gasUsed"]) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
err -> |
|
|
|
|
err |
|
|
|
@ -144,10 +146,11 @@ defmodule ExW3 do |
|
|
|
|
output_types = Enum.map(abi[name]["outputs"], fn x -> x["type"] end) |
|
|
|
|
types_signature = Enum.join(["(", Enum.join(output_types, ","), ")"]) |
|
|
|
|
output_signature = "#{name}(#{types_signature})" |
|
|
|
|
|
|
|
|
|
outputs = |
|
|
|
|
ABI.decode(output_signature, trim_output) |
|
|
|
|
|> List.first |
|
|
|
|
|> Tuple.to_list |
|
|
|
|
|> List.first() |
|
|
|
|
|> Tuple.to_list() |
|
|
|
|
|
|
|
|
|
outputs |
|
|
|
|
end |
|
|
|
@ -186,7 +189,9 @@ defmodule ExW3 do |
|
|
|
|
@spec encode_method_call(%{}, binary(), []) :: binary() |
|
|
|
|
@doc "Encodes data and appends it to the encoded method id" |
|
|
|
|
def encode_method_call(abi, name, input) do |
|
|
|
|
encoded_method_call = method_signature(abi, name) <> encode_data(types_signature(abi, name), input) |
|
|
|
|
encoded_method_call = |
|
|
|
|
method_signature(abi, name) <> encode_data(types_signature(abi, name), input) |
|
|
|
|
|
|
|
|
|
encoded_method_call |> Base.encode16(case: :lower) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
@ -272,17 +277,19 @@ defmodule ExW3 do |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
defp init_events(abi) do |
|
|
|
|
events = Enum.filter abi, fn {_, v} -> |
|
|
|
|
events = |
|
|
|
|
Enum.filter(abi, fn {_, v} -> |
|
|
|
|
v["type"] == "event" |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
signature_types_map = Enum.map events, fn {name, v} -> |
|
|
|
|
types = Enum.map v["inputs"], &Map.get(&1, "type") |
|
|
|
|
names = Enum.map v["inputs"], &Map.get(&1, "name") |
|
|
|
|
signature_types_map = |
|
|
|
|
Enum.map(events, fn {name, v} -> |
|
|
|
|
types = Enum.map(v["inputs"], &Map.get(&1, "type")) |
|
|
|
|
names = Enum.map(v["inputs"], &Map.get(&1, "name")) |
|
|
|
|
signature = Enum.join([name, "(", Enum.join(types, ","), ")"]) |
|
|
|
|
|
|
|
|
|
{"0x#{ExW3.encode_event(signature)}", %{signature: signature, names: names}} |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
Enum.into(signature_types_map, %{}) |
|
|
|
|
end |
|
|
|
@ -290,12 +297,13 @@ defmodule ExW3 do |
|
|
|
|
# Helpers |
|
|
|
|
|
|
|
|
|
def deploy_helper(bin, abi, args) do |
|
|
|
|
|
|
|
|
|
constructor_arg_data = |
|
|
|
|
if args[:args] do |
|
|
|
|
constructor_abi = Enum.find abi, fn {_, v} -> |
|
|
|
|
constructor_abi = |
|
|
|
|
Enum.find(abi, fn {_, v} -> |
|
|
|
|
v["type"] == "constructor" |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
if constructor_abi do |
|
|
|
|
{_, constructor} = constructor_abi |
|
|
|
|
input_types = Enum.map(constructor["inputs"], fn x -> x["type"] end) |
|
|
|
@ -322,7 +330,8 @@ defmodule ExW3 do |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def eth_call_helper(address, abi, method_name, args) do |
|
|
|
|
result = Ethereumex.HttpClient.eth_call(%{ |
|
|
|
|
result = |
|
|
|
|
Ethereumex.HttpClient.eth_call(%{ |
|
|
|
|
to: address, |
|
|
|
|
data: ExW3.encode_method_call(abi, method_name, args) |
|
|
|
|
}) |
|
|
|
@ -367,6 +376,7 @@ defmodule ExW3 do |
|
|
|
|
|
|
|
|
|
def handle_call({:call, {method_name, args}}, _from, state) do |
|
|
|
|
address = state[:address] |
|
|
|
|
|
|
|
|
|
if address do |
|
|
|
|
result = eth_call_helper(address, state[:abi], Atom.to_string(method_name), args) |
|
|
|
|
{:reply, result, state} |
|
|
|
@ -377,6 +387,7 @@ defmodule ExW3 do |
|
|
|
|
|
|
|
|
|
def handle_call({:send, {method_name, args, options}}, _from, state) do |
|
|
|
|
address = state[:address] |
|
|
|
|
|
|
|
|
|
if address do |
|
|
|
|
result = eth_send_helper(address, state[:abi], Atom.to_string(method_name), args, options) |
|
|
|
|
{:reply, result, state} |
|
|
|
@ -386,21 +397,24 @@ defmodule ExW3 do |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def handle_call({:tx_receipt, tx_hash}, _from, state) do |
|
|
|
|
receipt = ExW3.tx_receipt tx_hash |
|
|
|
|
receipt = ExW3.tx_receipt(tx_hash) |
|
|
|
|
events = state[:events] |
|
|
|
|
logs = receipt["logs"] |
|
|
|
|
formatted_logs = Enum.map logs, fn log -> |
|
|
|
|
topic = Enum.at log["topics"], 0 |
|
|
|
|
event = Map.get events, topic |
|
|
|
|
|
|
|
|
|
formatted_logs = |
|
|
|
|
Enum.map(logs, fn log -> |
|
|
|
|
topic = Enum.at(log["topics"], 0) |
|
|
|
|
event = Map.get(events, topic) |
|
|
|
|
|
|
|
|
|
if event do |
|
|
|
|
Enum.zip(event[:names], ExW3.decode_event(log["data"], event[:signature])) |> Enum.into(%{}) |
|
|
|
|
Enum.zip(event[:names], ExW3.decode_event(log["data"], event[:signature])) |
|
|
|
|
|> Enum.into(%{}) |
|
|
|
|
else |
|
|
|
|
nil |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
{:reply, {:ok, {receipt, formatted_logs}}, state} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
end |