Current section
Files
Jump to
Current section
Files
lib/web3/types/event.ex
defmodule Web3.Type.Event do
@moduledoc false
defstruct [
:name,
:anonymous,
:inputs,
:signature
]
defmacro __using__(opts) do
event = opts[:event]
input_names = event.inputs |> Enum.map(&elem(&1, 0))
event_module = Module.concat(__CALLER__.module, event.name)
quote do
defmodule unquote(event_module) do
@moduledoc """
#{unquote(to_definition(event))}
#{unquote(event.signature)}
"""
defstruct unquote(input_names)
def abi() do
unquote(Macro.escape(event))
end
end
@events {unquote(event.signature), unquote(event_module)}
end
end
@spec decode_log(atom(), %{data: binary(), topics: [String.t()]}) :: map()
def decode_log(event_module, %{data: data, topics: [signature | topics]}) do
%__MODULE__{signature: ^signature, inputs: inputs} = event_module.abi()
{indexed_inputs, data_inputs} =
inputs
|> Enum.split_with(&elem(&1, 2)[:indexed])
indexed_field_types =
indexed_inputs
|> Enum.map(&elem(&1, 1))
data_field_types =
data_inputs
|> Enum.map(&elem(&1, 1))
indexed_fields =
topics
|> Enum.map(&Web3.ABI.unhex/1)
|> Enum.zip(indexed_field_types)
|> Enum.map(fn {bytes, type} ->
{:ok, value, _} = Web3.ABI.TypeDecoder.decode_type(bytes, type, 0)
value
end)
{:ok, data_fields} = Web3.ABI.TypeDecoder.decode_data(data, data_field_types)
fields = build_event([], inputs, data_fields, indexed_fields)
struct!(event_module, fields)
end
def build_event(fields, [], _data, _indexed), do: fields
def build_event(fields, [{name, _type, meta} | inputs], data, indexed) do
if meta[:indexed] do
build_event([{name, hd(indexed)} | fields], inputs, data, tl(indexed))
else
build_event([{name, hd(data)} | fields], inputs, tl(data), indexed)
end
end
def to_definition(%__MODULE__{name: name, inputs: inputs, anonymous: anonymous}) do
param_types =
inputs
|> Enum.map(fn
{name, type, meta} ->
type = Web3.ABI.type_name(type)
if meta[:indexed] do
"#{type} indexed #{name}"
else
"#{type} #{name}"
end
end)
|> Enum.join(", ")
if anonymous do
"#{name}(#{param_types}) anonymous"
else
"#{name}(#{param_types})"
end
end
end