Current section

Files

Jump to
abi lib abi event.ex
Raw

lib/abi/event.ex

defmodule ABI.Event do
@doc ~S"""
Decodes an event, including handling parsing out data from topics.
## Examples
iex> "00000000000000000000000000000000000000000000000000000004a817c800"
...> |> Base.decode16!(case: :lower)
...> |> ABI.Event.decode_event(
...> [
...> "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" |> Base.decode16!(case: :lower),
...> "000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8" |> Base.decode16!(case: :lower),
...> "0000000000000000000000007795126b3ae468f44c901287de98594198ce38ea" |> Base.decode16!(case: :lower)
...> ],
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> })
{"Transfer",
%{
"amount" => 20_000_000_000,
"from" => <<252, 55, 141, 170, 149, 43, 167, 241, 99, 196, 161, 22, 40, 245, 90, 77, 245, 35, 179, 239>>,
"to" => <<178, 183, 193, 121, 95, 25, 251, 194, 143, 218, 119, 169, 94, 89, 237, 187, 139, 55, 9, 200>>
}}
"""
def decode_event(data, topics, function_selector) do
# First, split the types into indexed and not indexed
{indexed_types, non_indexed_types} =
Enum.split_with(function_selector.types, fn t -> Map.get(t, :indexed) end)
indexed_data =
indexed_types
|> Enum.zip(topics)
|> Enum.map(fn {type, topic} ->
[value] = ABI.TypeDecoder.decode_raw(topic, [type])
{type.name, value}
end)
|> Enum.into(%{})
non_indexed_data =
data
|> ABI.TypeDecoder.decode_raw(non_indexed_types)
|> Enum.zip(non_indexed_types)
|> Enum.map(fn {res, %{name: name}} -> {name, res} end)
|> Enum.into(%{})
{function_selector.function, Map.merge(indexed_data, non_indexed_data)}
end
@doc ~S"""
Returns the topic of an event, i.e. the first item that appears
in an Ethereum log for this event.
## Examples
iex> ABI.Event.event_topic(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> }
...> )
...> |> Base.encode16(case: :lower)
"ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
"""
def event_topic(function_selector) do
function_selector
|> ABI.FunctionSelector.encode()
|> ABI.Math.kec()
end
end