Onchain.Log (onchain v0.9.0)

Copy Markdown View Source

Event log parsing for Ethereum contract events.

Computes event topic hashes from signatures and decodes raw log data against event signatures with indexed parameter markers.

Limitations

  • Tuple-typed params (e.g. (uint256,address)) are not supported in event signatures. The comma-based parser cannot distinguish tuple-internal commas from param separators.
  • Indexed dynamic types (string, bytes, arrays) return the raw keccak256 topic hash since the original value is not recoverable from the log.

Error Format

  • Invalid signature: {:error, {:invalid_signature, input}}
  • Topic mismatch: {:error, {:decode_error, {:topic_mismatch, [expected: ..., got: ...]}}}
  • Decode errors: {:error, {:decode_error, reason}}

Security — signature is a trust boundary

Each parameter name in a signature is interned with String.to_atom/1 so the decoded map can use atom keys. The signature argument MUST be developer-controlled (a compile-time constant or value you author), never attacker-influenced input (request body, config supplied by a third party). Atoms are not garbage-collected, so routing untrusted signatures here is an atom-table-exhaustion (DoS) vector.

As a defence-in-depth bound — not a substitute for the contract above — decode_event/2 rejects signatures with more than 32 params and rejects any segment that is not a bounded identifier-shaped token before interning it ({:error, {:invalid_signature, _}}). This caps the per-call surface; it does not stop an attacker looping distinct valid names across many calls. The only structural fix is string-keyed output, a breaking change deliberately not taken here.

Functions

FunctionPurpose
event_topic/1Event signature → keccak256 topic hash
event_topic!/1Same, raises on error
decode_event/2Raw log + signature → decoded param map
decode_event!/2Same, raises on error

API Functions

FunctionArityDescriptionParam Kinds
decode_event!2Decode a raw log map. Raises on error.log: value, signature: value
decode_event2Decode a raw log map against an event signature with indexed markers.log: value, signature: value
event_topic!1Compute the keccak256 topic hash. Raises on error.signature: value
event_topic1Compute the keccak256 topic hash for an event signature.signature: value

Summary

Functions

Decode a raw log map against an event signature with indexed markers.

Decode a raw log map. Raises on error.

Compute the keccak256 topic hash for an event signature.

Compute the keccak256 topic hash. Raises on error.

Functions

decode_event(arg1, signature)

@spec decode_event(map(), String.t()) :: {:ok, map()} | {:error, term()}

Decode a raw log map against an event signature with indexed markers.

Parameters

  • log - Raw log map with :topics (list of hex strings) and :data (hex string) keys (value)
  • signature - Event signature with indexed markers, e.g. "Transfer(address indexed from, address indexed to, uint256 value)". MUST be developer-controlled — param names are interned as atoms; untrusted signatures are an atom-table DoS vector (see module "Security"). (value)

Returns

Map with atom keys for each decoded parameter ({:ok, map} | {:error, term})

# descripex:contract
%{
  params: %{
    log: %{
      description: "Raw log map with :topics (list of hex strings) and :data (hex string) keys",
      kind: :value
    },
    signature: %{
      description: "Event signature with indexed markers, e.g. \"Transfer(address indexed from, address indexed to, uint256 value)\". MUST be developer-controlled — param names are interned as atoms; untrusted signatures are an atom-table DoS vector (see module \"Security\").",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, map} | {:error, term}",
    description: "Map with atom keys for each decoded parameter",
    example: "%{from: \"0xAb5...\", to: \"0xCd9...\", value: 1000000}"
  }
}

decode_event!(log, signature)

@spec decode_event!(map(), String.t()) :: map()

Decode a raw log map. Raises on error.

Parameters

  • log - Raw log map with :topics and :data keys (value)
  • signature - Event signature with indexed markers. MUST be developer-controlled — param names are interned as atoms; untrusted signatures are an atom-table DoS vector (see module "Security" and decode_event/2). (value)

Returns

Map with atom keys for each decoded parameter (map)

# descripex:contract
%{
  params: %{
    log: %{description: "Raw log map with :topics and :data keys", kind: :value},
    signature: %{
      description: "Event signature with indexed markers. MUST be developer-controlled — param names are interned as atoms; untrusted signatures are an atom-table DoS vector (see module \"Security\" and decode_event/2).",
      kind: :value
    }
  },
  returns: %{
    type: :map,
    description: "Map with atom keys for each decoded parameter"
  }
}

event_topic(signature)

@spec event_topic(String.t()) :: {:ok, String.t()} | {:error, term()}

Compute the keccak256 topic hash for an event signature.

Parameters

  • signature - Event signature without param names, e.g. "Transfer(address,address,uint256)" (value)

Returns

0x-prefixed 32-byte keccak256 hash ({:ok, hex_string} | {:error, term})

# descripex:contract
%{
  params: %{
    signature: %{
      description: "Event signature without param names, e.g. \"Transfer(address,address,uint256)\"",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, hex_string} | {:error, term}",
    description: "0x-prefixed 32-byte keccak256 hash",
    example: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
  }
}

event_topic!(signature)

@spec event_topic!(String.t()) :: String.t()

Compute the keccak256 topic hash. Raises on error.

Parameters

  • signature - Event signature string (value)

Returns

0x-prefixed 32-byte keccak256 hash (string)

# descripex:contract
%{
  params: %{signature: %{description: "Event signature string", kind: :value}},
  returns: %{type: :string, description: "0x-prefixed 32-byte keccak256 hash"}
}