ABI.Event (hieroglyph v1.5.0)

Copy Markdown View Source

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

FunctionArityDescriptionParam Kinds
canonical2Render the canonical signature string of an event for hashing or display, optionally including indexed and parameter-name annotations.function_selector: value, opts: value
event_signature1Compute the keccak-256 hash of the event's canonical signature, used as topics[0] in event logs.function_selector: value
encode_event_topics2Build an eth_getLogs topic filter list from an event selector and indexed argument values.function_selector: value, indexed_values: value
decode_event4Decode 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

decode_error()

@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_mismatchtopics[0] did not match keccak256(canonical_signature).
  • :topics_length_mismatch — number of topics did not match the indexed-parameter count (plus the implicit topics[0] slot when check_event_signature: true).
  • :malformed_data — non-indexed payload failed to decode (truncated, wrong types, or otherwise inconsistent with function_selector.types).
  • :strict_violationstrict: true rejected non-canonical padding, trailing bytes, or string/bytes length prefixes beyond the available data.

Functions

canonical(function_selector, opts \\ [])

@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)"

decode_event(data, topics, function_selector, opts \\ [])

@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.

encode_event_topics(function_selector, indexed_values)

@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
]

event_signature(function_selector)

@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"