Per the Solidity ABI spec, indexed parameters of dynamic types (string, bytes, T[], tuples, structs) are stored in log topics as keccak256(value), not as their raw ABI encoding.
This is about event topic decoding, not the encoding path (distinct from the encoding concern in #17).
ABI.Event.decode_event/4 (lib/abi/event.ex:111-118) zips indexed_types_full with topics and calls TypeDecoder.decode_raw/3 on each topic regardless of whether the type is dynamic. ABI.FunctionSelector.is_dynamic?/1 exists (function_selector.ex:459-466) but isn't consulted here.
For :string / :bytes / T[] indexed params, the decoder expects length-prefixed ABI data (type_decoder.ex:235-243) — attempting to decode a bare 32-byte keccak hash as ABI data can raise or produce invalid values.
Example:
event Named(string indexed name, uint256 value);
// emit Named("alice", 42);
The first indexed param arrives in topics as keccak256("alice"). It should surface as that opaque 32-byte hash (unrecoverable to the original string), not as a decoded value.
Suggested fix: check is_dynamic?/1 in the indexed loop; return the raw topic bytes (or another explicit opaque wrapper) for dynamic indexed params, with a doc note that the original value is not recoverable from the topic alone.
Happy to send a PR if this direction works.
Per the Solidity ABI spec, indexed parameters of dynamic types (
string,bytes,T[], tuples, structs) are stored in log topics askeccak256(value), not as their raw ABI encoding.This is about event topic decoding, not the encoding path (distinct from the encoding concern in #17).
ABI.Event.decode_event/4(lib/abi/event.ex:111-118) zipsindexed_types_fullwithtopicsand callsTypeDecoder.decode_raw/3on each topic regardless of whether the type is dynamic.ABI.FunctionSelector.is_dynamic?/1exists (function_selector.ex:459-466) but isn't consulted here.For
:string/:bytes/T[]indexed params, the decoder expects length-prefixed ABI data (type_decoder.ex:235-243) — attempting to decode a bare 32-byte keccak hash as ABI data can raise or produce invalid values.Example:
The first indexed param arrives in topics as
keccak256("alice"). It should surface as that opaque 32-byte hash (unrecoverable to the original string), not as a decoded value.Suggested fix: check
is_dynamic?/1in the indexed loop; return the raw topic bytes (or another explicit opaque wrapper) for dynamic indexed params, with a doc note that the original value is not recoverable from the topic alone.Happy to send a PR if this direction works.