Decodes Ethereum event log data into Solidity-typed arguments.
Splits the topic list (indexed parameters) from the data blob (non-indexed
parameters) per the ABI specification, and optionally verifies that
topics[0] matches the keccak256 hash of the event signature.
API Functions
| Function | Arity | Description | Param Kinds |
|---|---|---|---|
canonical | 2 | Render the canonical signature string of an event for hashing or display, optionally including indexed and parameter-name annotations. | function_selector: value, opts: value |
event_signature | 1 | Compute the keccak-256 hash of the event's canonical signature, used as topics[0] in event logs. | function_selector: value |
encode_event_topics | 2 | Build an eth_getLogs topic filter list from an event selector and indexed argument values. | function_selector: value, indexed_values: value |
decode_event | 4 | Decode an Ethereum event log, splitting indexed parameters from topics and non-indexed parameters from the data blob, optionally verifying topics[0] against the event signature. | data: exchange_data, topics: exchange_data, function_selector: value, opts: value |
Summary
Types
Closed error set returned by decode_event/4.
Functions
Returns the canonical form of this event topic. Pass in indexed: true
to include "indexed" keywords.
Decodes an event, including handling parsing out data from topics.
Builds an eth_getLogs topic filter list for indexed event arguments.
Returns the signature of an event, i.e. the first item that appears in an Ethereum log for this event.
Types
@type decode_error() :: {:event_signature_mismatch, %{expected: binary(), got: binary()}} | {:topics_length_mismatch, length_pair()} | {:malformed_data, String.t()} | {:strict_violation, term()}
Closed error set returned by decode_event/4.
:event_signature_mismatch—topics[0]did not matchkeccak256(canonical_signature).:topics_length_mismatch— number of topics did not match the indexed-parameter count (plus the implicittopics[0]slot whencheck_event_signature: true).:malformed_data— non-indexed payload failed to decode (truncated, wrong types, or otherwise inconsistent withfunction_selector.types).:strict_violation—strict: truerejected non-canonical padding, trailing bytes, or string/bytes length prefixes beyond the available data.
Functions
@spec canonical( ABI.FunctionSelector.t(), keyword() ) :: String.t()
Returns the canonical form of this event topic. Pass in indexed: true
to include "indexed" keywords.
Examples
iex> ABI.Event.canonical(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> }
...> )
"Transfer(address,address,uint256)"
iex> ABI.Event.canonical(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> },
...> names: true
...> )
"Transfer(address from,address to,uint256 amount)"
iex> ABI.Event.canonical(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> },
...> indexed: true
...> )
"Transfer(address indexed,address indexed,uint256)"
iex> ABI.Event.canonical(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> },
...> indexed: true,
...> names: true
...> )
"Transfer(address indexed from,address indexed to,uint256 amount)"
@spec decode_event(binary(), [binary()], ABI.FunctionSelector.t(), keyword()) :: {:ok, String.t() | nil, map()} | {:error, decode_error()}
Decodes an event, including handling parsing out data from topics.
Returns {:ok, function_name, args_map} on success, or {:error, reason} where
reason is one of the variants in decode_error/0.
Examples
iex> ABI.Event.decode_event(
...> ~h[0x00000000000000000000000000000000000000000000000000000004a817c800],
...> [
...> ~h[0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef],
...> ~h[0x000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
...> ~h[0x0000000000000000000000007795126b3ae468f44c901287de98594198ce38ea]
...> ],
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> })
{:ok,
"Transfer", %{
"amount" => 20000000000,
"from" => ~h[0xb2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
"to" => ~h[0x7795126b3ae468f44c901287de98594198ce38ea]
}}
iex> ABI.Event.decode_event(
...> ~h[0x00000000000000000000000000000000000000000000000000000004a817c800],
...> [
...> ~h[0x0000000000000000000000000000000000000000000000000000000000000001],
...> ~h[0x000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
...> ~h[0x0000000000000000000000007795126b3ae468f44c901287de98594198ce38ea]
...> ],
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> })
{:error,
{:event_signature_mismatch,
%{
expected: ~h[0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef],
got: ~h[0x0000000000000000000000000000000000000000000000000000000000000001]
}}}
iex> ABI.Event.decode_event(
...> ~h[0x00000000000000000000000000000000000000000000000000000004a817c800],
...> [
...> ~h[0x000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
...> ~h[0x0000000000000000000000007795126b3ae468f44c901287de98594198ce38ea]
...> ],
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> })
{:error, {:topics_length_mismatch, %{got: 2, expected: 3}}}
iex> ABI.Event.decode_event(
...> ~h[0x00000000000000000000000000000000000000000000000000000004a817c800],
...> [
...> ~h[0x000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
...> ~h[0x0000000000000000000000007795126b3ae468f44c901287de98594198ce38ea]
...> ],
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> },
...> check_event_signature: false
...> )
{:ok,
"Transfer", %{
"amount" => 20000000000,
"from" => ~h[0xb2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
"to" => ~h[0x7795126b3ae468f44c901287de98594198ce38ea]
}}When the non-indexed payload bytes are truncated or wrongly typed, the underlying
decoder previously raised; the function now wraps that path and returns
{:error, {:malformed_data, msg}} with a human-readable description.
@spec encode_event_topics(ABI.FunctionSelector.t(), [any() | :any]) :: [ topic_filter() ]
Builds an eth_getLogs topic filter list for indexed event arguments.
Pass indexed argument values in event order. Use :any for an unfiltered
indexed slot. Non-anonymous events include topics[0]; anonymous events
parsed from JSON ABI omit it.
Examples
iex> ABI.Event.encode_event_topics(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"}
...> ]
...> },
...> [~h[0xb2b7c1795f19fbc28fda77a95e59edbb8b3709c8], :any]
...> )
[
~h[0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef],
~h[0x000000000000000000000000b2b7c1795f19fbc28fda77a95e59edbb8b3709c8],
:any
]
@spec event_signature(ABI.FunctionSelector.t()) :: binary()
Returns the signature of an event, i.e. the first item that appears in an Ethereum log for this event.
Examples
iex> ABI.Event.event_signature(
...> %ABI.FunctionSelector{
...> function: "Transfer",
...> types: [
...> %{type: :address, name: "from", indexed: true},
...> %{type: :address, name: "to", indexed: true},
...> %{type: {:uint, 256}, name: "amount"},
...> ]
...> }
...> )
...> |> to_hex()
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"