4
0
Fork 0

Added bytes to string method

contracts
hswick 7 years ago
parent df0bbd35d5
commit 6cf9295896
  1. 170
      lib/exw3.ex
  2. 4
      mix.exs
  3. 1
      mix.lock
  4. 31
      test/exw3_test.exs

@ -1,78 +1,96 @@
defmodule ExW3 do
def reformat_abi abi do
Map.new Enum.map(abi, fn x -> {x["name"], x} end)
def reformat_abi(abi) do
Map.new(Enum.map(abi, fn x -> {x["name"], x} end))
end
def load_abi file_path do
file = File.read Path.join(System.cwd, file_path)
def load_abi(file_path) do
file = File.read(Path.join(System.cwd(), file_path))
case file do
{:ok, abi} -> reformat_abi Poison.Parser.parse! abi
{:ok, abi} -> reformat_abi(Poison.Parser.parse!(abi))
err -> err
end
end
def decode_output abi, name, output do
{:ok, trim_output} = String.slice(output, 2..String.length(output)) |> Base.decode16(case: :lower)
output_types = Enum.map abi[name]["outputs"], fn x -> x["type"] end
output_signature = Enum.join [name, "(", Enum.join(output_types, ")"), ")"]
def decode_output(abi, name, output) do
{:ok, trim_output} =
String.slice(output, 2..String.length(output)) |> Base.decode16(case: :lower)
output_types = Enum.map(abi[name]["outputs"], fn x -> x["type"] end)
output_signature = Enum.join([name, "(", Enum.join(output_types, ")"), ")"])
ABI.decode(output_signature, trim_output)
end
def encode_inputs abi, name, inputs do
input_types = Enum.map abi[name]["inputs"], fn x -> x["type"] end
input_signature = Enum.join [name, "(", Enum.join(input_types, ","), ")"]
ABI.encode(input_signature, inputs) |> Base.encode16(case: :lower)
def encode_input(abi, name, input) do
if abi[name]["inputs"] do
input_types = Enum.map(abi[name]["inputs"], fn x -> x["type"] end)
input_signature = Enum.join([name, "(", Enum.join(input_types, ","), ")"])
ABI.encode(input_signature, input) |> Base.encode16(case: :lower)
else
raise "#{name} method not found with the given abi"
end
end
def bytes_to_string bytes do
bytes
|> Base.encode16(case: :lower)
|> String.replace_trailing("0", "")
|> Hexate.decode
end
def accounts do
case Ethereumex.HttpClient.eth_accounts do
case Ethereumex.HttpClient.eth_accounts() do
{:ok, accounts} -> accounts
err -> err
end
end
#Converts ethereum hex string to decimal number
def to_decimal hex_string do
# Converts ethereum hex string to decimal number
def to_decimal(hex_string) do
hex_string
|> String.slice(2..-1)
|> String.to_integer(16)
end
def block_number do
case Ethereumex.HttpClient.eth_block_number do
{:ok, block_number} ->
case Ethereumex.HttpClient.eth_block_number() do
{:ok, block_number} ->
block_number |> to_decimal
err -> err
err ->
err
end
end
def balance account do
def balance(account) do
case Ethereumex.HttpClient.eth_get_balance(account) do
{:ok, balance} ->
{:ok, balance} ->
balance |> to_decimal
err -> err
err ->
err
end
end
def keys_to_decimal map, keys do
def keys_to_decimal(map, keys) do
Map.new(
Enum.map keys, fn k ->
{ k, Map.get(map, k) |> to_decimal }
end
Enum.map(keys, fn k ->
{k, Map.get(map, k) |> to_decimal}
end)
)
end
def tx_receipt tx_hash do
def tx_receipt(tx_hash) do
case Ethereumex.HttpClient.eth_get_transaction_receipt(tx_hash) do
{:ok, receipt} ->
receipt
#Map.merge receipt, keys_to_decimal(receipt, ["blockNumber", "cumulativeGasUsed", "gasUsed"])
err -> err
{:ok, receipt} ->
Map.merge receipt, keys_to_decimal(receipt, ["blockNumber", "cumulativeGasUsed", "gasUsed"])
err ->
err
end
end
def block block_number do
def block(block_number) do
case Ethereumex.HttpClient.eth_get_block_by_number(block_number, true) do
{:ok, block} -> block
err -> err
@ -91,9 +109,9 @@ defmodule ExW3 do
defmodule Contract do
use Agent
def at(abi, address) do
{ :ok, pid } = Agent.start_link(fn -> %{abi: abi, address: address} end)
{:ok, pid} = Agent.start_link(fn -> %{abi: abi, address: address} end)
pid
end
@ -110,40 +128,55 @@ defmodule ExW3 do
def deploy(bin_filename, options) do
{:ok, bin} = File.read(Path.join(System.cwd(), bin_filename))
tx = %{
from: options[:from],
data: bin,
gas: options[:gas]
}
{:ok, tx_receipt_id} = Ethereumex.HttpClient.eth_send_transaction(tx)
{:ok, tx_receipt} = Ethereumex.HttpClient.eth_get_transaction_receipt(tx_receipt_id)
tx_receipt["contractAddress"]
end
def method(contract_agent, name, args \\ [], options \\ %{}) do
if get(contract_agent, :abi)[name]["constant"] do
data = ExW3.encode_inputs(get(contract_agent, :abi), name, args)
{:ok, output } = Ethereumex.HttpClient.eth_call(%{
to: get(contract_agent, :address),
data: data
})
[ :ok ] ++ ExW3.decode_output(get(contract_agent, :abi), name, output) |> List.to_tuple
def method(contract_agent, method_name, args \\ [], options \\ %{}) do
method_name =
case method_name |> is_atom do
true -> Inflex.camelize(method_name, :lower)
false -> method_name
end
input = ExW3.encode_input(get(contract_agent, :abi), method_name, args)
if get(contract_agent, :abi)[method_name]["constant"] do
{:ok, output} =
Ethereumex.HttpClient.eth_call(%{
to: get(contract_agent, :address),
data: input
})
([:ok] ++ ExW3.decode_output(get(contract_agent, :abi), method_name, output)) |> List.to_tuple()
else
Ethereumex.HttpClient.eth_send_transaction(Map.merge(%{
to: get(contract_agent, :address),
data: ExW3.encode_inputs(get(contract_agent, :abi), name, args)
}, options))
Ethereumex.HttpClient.eth_send_transaction(
Map.merge(
%{
to: get(contract_agent, :address),
data: input
},
options
)
)
end
end
end
defmodule EventPublisher do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, %{ block_number: ExW3.block_number})
GenServer.start_link(__MODULE__, %{block_number: ExW3.block_number()})
end
def init(state) do
@ -157,16 +190,15 @@ defmodule ExW3 do
end
def handle_info(:block, state) do
block_number = ExW3.block_number
block = ExW3.block block_number
block_number = ExW3.block_number()
block = ExW3.block(block_number)
tx_receipts = Enum.map block["transactions"], fn tx -> ExW3.tx_receipt(tx["hash"]) end
tx_receipts = Enum.map(block["transactions"], fn tx -> ExW3.tx_receipt(tx["hash"]) end)
for logs <- Enum.map(tx_receipts, fn receipt -> receipt["logs"] end) do
for log <- logs do
for topic <- log["topics"] do
PubSub.publish String.slice(topic, 2..-1), log["data"]
PubSub.publish(String.slice(topic, 2..-1), log["data"])
end
end
end
@ -178,30 +210,32 @@ defmodule ExW3 do
defp schedule_block() do
Process.send_after(self(), :block, 1000)
end
end
def decode_event(data, signature) do
fs = ABI.FunctionSelector.decode(signature)
data
|> Base.decode16!(case: :lower)
|> ABI.TypeDecoder.decode(fs)
end
defmodule EventSubscriber do
def start(state) do
spawn(fn -> loop(state) end)
def start_link(signature, callback) do
pid = spawn(fn -> loop(%{callback: callback, signature: signature}) end)
ExW3.EventPublisher.subscribe(pid, ExW3.encode_event(signature))
{:ok, pid}
end
def loop(state) do
receive do
message ->
apply(state[:callback], [message])
apply(state[:callback], [
ExW3.decode_event(String.slice(message, 2..-1), state[:signature])
])
loop(state)
end
end
end
def subscribe signature, callback do
pid = ExW3.EventSubscriber.start %{callback: callback}
ExW3.EventPublisher.subscribe pid, ExW3.encode_event(signature)
end
end
end

@ -31,7 +31,9 @@ defmodule ExW3.Mixfile do
{:ethereumex, "~> 0.3.2"},
{:abi, "~> 0.1.8"},
{:poison, "~> 3.1"},
{:pubsub, "~> 1.0"}
{:pubsub, "~> 1.0"},
{:inflex, "~> 1.10.0" },
{:hexate, ">= 0.6.0"}
]
end
end

@ -8,6 +8,7 @@
"hexate": {:hex, :hexate, "0.6.1", "1cea42e462c1daa32223127d4752e71016c3d933d492b9bb7fa4709a4a0fd50d", [:mix], [], "hexpm"},
"httpoison": {:hex, :httpoison, "1.0.0", "1f02f827148d945d40b24f0b0a89afe40bfe037171a6cf70f2486976d86921cd", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"inflex": {:hex, :inflex, "1.10.0", "8366a7696e70e1813aca102e61274addf85d99f4a072b2f9c7984054ea1b9d29", [:mix], [], "hexpm"},
"keccakf1600": {:hex, :keccakf1600_orig, "2.0.0", "0a7217ddb3ee8220d449bbf7575ec39d4e967099f220a91e3dfca4dbaef91963", [:rebar3], [], "hexpm"},
"libsecp256k1": {:hex, :libsecp256k1, "0.1.3", "57468b986af7c9633527875f71c7ca08bf4150b07b38a60d5bd48fba299ff6c1", [:rebar3], [], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},

@ -50,17 +50,17 @@ defmodule EXW3Test do
storage = ExW3.Contract.at context[:simple_storage_abi], contract_address
{:ok, result} = ExW3.Contract.method(storage, "get")
{:ok, result} = ExW3.Contract.method(storage, :get)
assert result == 0
{:ok, tx_hash} = ExW3.Contract.method(storage, "set", [1], %{from: Enum.at(context[:accounts], 0)})
{:ok, tx_hash} = ExW3.Contract.method(storage, :set, [1], %{from: Enum.at(context[:accounts], 0)})
receipt = ExW3.tx_receipt tx_hash
#IO.inspect ExW3.block receipt["blockNumber"]
{:ok, result} = ExW3.Contract.method(storage, "get")
{:ok, result} = ExW3.Contract.method(storage, :get)
assert result == 1
@ -79,9 +79,24 @@ defmodule EXW3Test do
{:ok, event_pub} = ExW3.EventPublisher.start_link
ExW3.subscribe("Simple(uint256,bytes32)", fn event -> IO.inspect event end)
{:ok, pid} = ExW3.EventSubscriber.start_link(
"Simple(uint256,bytes32)",
fn event_data ->
str =
event_data
|> Enum.at(1)
|> ExW3.bytes_to_string
{:ok, tx_hash} = ExW3.Contract.method(event_tester, "simple", ["hello, there!"], %{from: Enum.at(context[:accounts], 0)})
assert str == "Hello, World!"
end
)
{:ok, tx_hash} = ExW3.Contract.method(
event_tester,
:simple,
["Hello, World!"],
%{from: Enum.at(context[:accounts], 0)}
)
receipt = ExW3.tx_receipt tx_hash
@ -91,7 +106,7 @@ defmodule EXW3Test do
assert String.slice(Enum.at(topic, 0), 2..-1) == ExW3.encode_event("Simple(uint256,bytes32)")
:timer.sleep(5000)
:timer.sleep(2000)
end
@ -108,12 +123,12 @@ defmodule EXW3Test do
arr = [1, 2, 3, 4, 5]
{:ok, result} = ExW3.Contract.method(array_tester, "staticUint", [arr])
{:ok, result} = ExW3.Contract.method array_tester, :static_int, [arr]
assert result == arr
#0x5d4e0342
{:ok, result} = ExW3.Contract.method(array_tester, "dynamicUint", [arr])
{:ok, result} = ExW3.Contract.method array_tester, :dynamic_uint, [arr]
assert result == arr

Loading…
Cancel
Save