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 |
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.
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()}
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).
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 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"