-module(gleeth@events). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/events.gleam"). -export([decode_logs/2, get_events/5, get_events_by_name/6]). -export_type([event_result/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Query and decode contract events in a single call.\n" "\n" " Combines `methods.get_logs` with ABI event decoding so you don't have\n" " to manually match topic hashes and decode parameters.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(abi) = json.parse_abi(erc20_abi_json)\n" " let assert Ok(decoded) = events.get_events(\n" " provider,\n" " \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\n" " abi,\n" " \"0x100000\",\n" " \"latest\",\n" " )\n" " // decoded: List(EventResult) - each with event name and typed params\n" " ```\n" ). -type event_result() :: {decoded, gleeth@ethereum@abi@events:decoded_log(), gleeth@ethereum@types:log()} | {unknown, gleeth@ethereum@types:log()}. -file("src/gleeth/events.gleam", 100). ?DOC( " Decode a list of raw logs against an ABI. Useful when you already\n" " have logs from another source (e.g. a transaction receipt).\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let results = events.decode_logs(receipt.logs, abi)\n" " ```\n" ). -spec decode_logs( list(gleeth@ethereum@types:log()), list(gleeth@ethereum@abi@json:abi_entry()) ) -> list(event_result()). decode_logs(Logs, Abi) -> gleam@list:map( Logs, fun(Log) -> case gleeth@ethereum@abi@events:decode_log(Log, Abi) of {ok, Decoded} -> {decoded, Decoded, Log}; {error, _} -> {unknown, Log} end end ). -file("src/gleeth/events.gleam", 46). ?DOC( " Query logs for a contract and decode them against the provided ABI.\n" " Logs that match an event in the ABI are decoded; unmatched logs are\n" " returned as `Unknown` so no data is lost.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(events) = events.get_events(\n" " provider, \"0xA0b8...\", abi, \"0x100000\", \"latest\",\n" " )\n" " ```\n" ). -spec get_events( gleeth@provider:provider(), binary(), list(gleeth@ethereum@abi@json:abi_entry()), binary(), binary() ) -> {ok, list(event_result())} | {error, gleeth@rpc@types:gleeth_error()}. get_events(Provider, Address, Abi, From_block, To_block) -> gleam@result:'try'( gleeth@rpc@methods:get_logs(Provider, From_block, To_block, Address, []), fun(Logs) -> {ok, decode_logs(Logs, Abi)} end ). -file("src/gleeth/events.gleam", 119). -spec compute_event_topic(list(gleeth@ethereum@abi@json:abi_entry()), binary()) -> binary(). compute_event_topic(Abi, Event_name) -> Found = gleam@list:find(Abi, fun(Entry) -> case Entry of {event_entry, Name, _} -> Name =:= Event_name; _ -> false end end), case Found of {ok, {event_entry, Name@1, Inputs}} -> Types = gleam@list:map(Inputs, fun(P) -> erlang:element(3, P) end), gleeth@ethereum@abi@events:event_topic_hex(Name@1, Types); _ -> <<""/utf8>> end. -file("src/gleeth/events.gleam", 69). ?DOC( " Query logs for a specific event name. Filters by the event's topic0 hash,\n" " so only matching logs are returned from the RPC.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(transfers) = events.get_events_by_name(\n" " provider, \"0xA0b8...\", abi, \"Transfer\", \"0x100000\", \"latest\",\n" " )\n" " ```\n" ). -spec get_events_by_name( gleeth@provider:provider(), binary(), list(gleeth@ethereum@abi@json:abi_entry()), binary(), binary(), binary() ) -> {ok, list(event_result())} | {error, gleeth@rpc@types:gleeth_error()}. get_events_by_name(Provider, Address, Abi, Event_name, From_block, To_block) -> Topic0 = compute_event_topic(Abi, Event_name), Topics = case Topic0 of <<""/utf8>> -> []; T -> [T] end, gleam@result:'try'( gleeth@rpc@methods:get_logs( Provider, From_block, To_block, Address, Topics ), fun(Logs) -> {ok, decode_logs(Logs, Abi)} end ).