Current section

Files

Jump to
w3ws lib w3ws util.ex
Raw

lib/w3ws/util.ex

defmodule W3WS.Util do
@moduledoc """
Utility functions
"""
require Logger
@doc """
Convert a binary to hex
## Examples
iex> to_hex(<<1, 2, 3>>)
"0x010203"
iex> to_hex(1)
"0x1"
"""
@spec to_hex(binary() | integer()) :: String.t()
def to_hex(int) when is_integer(int), do: "0x" <> Integer.to_string(int, 16)
def to_hex(binary), do: "0x" <> Base.encode16(binary, case: :lower)
@doc """
Convert a hex string to a binary
## Examples
iex> from_hex("0x010203")
<<1, 2, 3>>
iex> from_hex("0x")
""
iex> from_hex("")
""
"""
@spec from_hex(String.t()) :: binary()
def from_hex("0x" <> hex), do: from_hex(hex)
def from_hex(hex), do: Base.decode16!(hex, case: :lower)
@doc """
Convert a hex string to an integer
## Examples
iex> integer_from_hex("0x7")
7
"""
@spec integer_from_hex(String.t()) :: integer()
def integer_from_hex("0x" <> hex) do
{int, ""} = Integer.parse(hex, 16)
int
end
@doc """
Calculate the keccak256 hash of a binary, optionally encoding as hex
## Examples
iex> keccak("foo", hex?: true)
"0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d"
"""
@spec keccak(binary, Keyword.t()) :: String.t()
def keccak(binary, opts \\ []) do
result = ExKeccak.hash_256(binary)
case Keyword.get(opts, :hex?, false) do
true -> to_hex(result)
false -> result
end
end
@doc """
Try to decode an event if an ABI is present
"""
@spec maybe_decode_event(W3WS.Env.t(), W3WS.ABI.t() | nil) :: W3WS.Env.t()
def maybe_decode_event(env, nil) do
W3WS.Env.with_event(env, W3WS.Event.from_raw_event(env.raw, nil, nil))
end
def maybe_decode_event(env, abi) do
{selector, decoded_data} =
case W3WS.ABI.decode_event(env.raw.data, abi, env.raw.topics) do
{:ok, selector, decoded_data} ->
{selector, decoded_data}
{:error, _} = err ->
Logger.warning("unable to decode event error=#{inspect(err)} event=#{inspect(env.raw)}")
{nil, nil}
end
W3WS.Env.with_event(env, W3WS.Event.from_raw_event(env.raw, selector, decoded_data))
end
@doc """
Try to decode the event with the given ABI and apply the handler.
The handler is always called, even if the event could not be
decoded.
"""
@spec decode_apply(W3WS.Env.t(), W3WS.ABI.t() | nil, W3WS.Handler.t(), any()) ::
pid() | {pid(), reference()}
def decode_apply(env, abi, handler, handler_state) do
env
|> maybe_decode_event(abi)
|> W3WS.Handler.apply_handler(handler, handler_state)
end
@doc """
Resolve the ABI from the given options
## Examples
iex> resolve_abi(abi: [])
[]
iex> resolve_abi(abi: nil)
nil
iex> resolve_abi(abi: [], abi_files: ["./test/support/files/test_abi.json"])
[
%ABI.FunctionSelector{
function: "Transfer",
method_id: <<221, 242, 82, 173>>,
type: :event,
inputs_indexed: [false, false, false],
state_mutability: nil,
input_names: ["from", "to", "value"],
types: [:address, :address, {:uint, 256}],
returns: [],
return_names: []
}
]
"""
def resolve_abi(opts) do
cond do
opts[:abi_files] ->
W3WS.ABI.from_files(opts[:abi_files])
opts[:abi] ->
W3WS.ABI.from_abi(opts[:abi])
true ->
nil
end
end
end