-module(gleeth@ethereum@abi@decode). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/ethereum/abi/decode.gleam"). -export([decode/2, decode_single/2]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/gleeth/ethereum/abi/decode.gleam", 235). ?DOC(" Read `length` bytes from data starting at offset.\n"). -spec read_bytes_at(bitstring(), integer(), integer()) -> {ok, bitstring()} | {error, gleeth@ethereum@abi@types:abi_error()}. read_bytes_at(Data, Offset, Length) -> case gleam_stdlib:bit_array_slice(Data, Offset, Length) of {ok, Bytes} -> {ok, Bytes}; {error, _} -> {error, {decode_error, <<<<<<<<<<"Data too short: need "/utf8, (erlang:integer_to_binary(Length))/binary>>/binary, " bytes at offset "/utf8>>/binary, (erlang:integer_to_binary(Offset))/binary>>/binary, ", have "/utf8>>/binary, (erlang:integer_to_binary(erlang:byte_size(Data)))/binary>>}} end. -file("src/gleeth/ethereum/abi/decode.gleam", 120). -spec decode_address_at(bitstring(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_address_at(Data, Offset) -> gleam@result:'try'( read_bytes_at(Data, Offset, 32), fun(Slot) -> case gleam_stdlib:bit_array_slice(Slot, 12, 20) of {ok, Addr_bytes} -> Hex_str = <<"0x"/utf8, (string:lowercase( gleam_stdlib:base16_encode(Addr_bytes) ))/binary>>, {ok, {address_value, Hex_str}}; {error, _} -> {error, {decode_error, <<"Failed to extract address bytes"/utf8>>}} end end ). -file("src/gleeth/ethereum/abi/decode.gleam", 138). -spec decode_fixed_bytes_at(bitstring(), integer(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_fixed_bytes_at(Data, Offset, Size) -> gleam@result:'try'( read_bytes_at(Data, Offset, 32), fun(Slot) -> case gleam_stdlib:bit_array_slice(Slot, 0, Size) of {ok, Bytes} -> {ok, {fixed_bytes_value, Bytes}}; {error, _} -> {error, {decode_error, <<"Failed to extract fixed bytes"/utf8>>}} end end ). -file("src/gleeth/ethereum/abi/decode.gleam", 255). ?DOC(" Convert a BitArray to an unsigned integer (big-endian).\n"). -spec bytes_to_uint(bitstring(), integer(), integer()) -> integer(). bytes_to_uint(Data, Index, Acc) -> case gleam_stdlib:bit_array_slice(Data, Index, 1) of {ok, <>} -> bytes_to_uint(Data, Index + 1, erlang:'bsl'(Acc, 8) + Byte); _ -> Acc end. -file("src/gleeth/ethereum/abi/decode.gleam", 229). ?DOC(" Read 32 bytes at the given offset and interpret as a big-endian unsigned int.\n"). -spec read_uint256_at(bitstring(), integer()) -> {ok, integer()} | {error, gleeth@ethereum@abi@types:abi_error()}. read_uint256_at(Data, Offset) -> gleam@result:'try'( read_bytes_at(Data, Offset, 32), fun(Slot) -> {ok, bytes_to_uint(Slot, 0, 0)} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 92). -spec decode_uint_at(bitstring(), integer(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_uint_at(Data, Offset, Bit_size) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Raw) -> Mask = erlang:'bsl'(1, Bit_size) - 1, {ok, {uint_value, erlang:'band'(Raw, Mask)}} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 103). -spec decode_int_at(bitstring(), integer(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_int_at(Data, Offset, Bit_size) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Raw) -> Mask = erlang:'bsl'(1, Bit_size) - 1, Masked = erlang:'band'(Raw, Mask), Sign_bit = erlang:'bsl'(1, Bit_size - 1), Value = case erlang:'band'(Masked, Sign_bit) /= 0 of true -> Masked - erlang:'bsl'(1, Bit_size); false -> Masked end, {ok, {int_value, Value}} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 133). -spec decode_bool_at(bitstring(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_bool_at(Data, Offset) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Raw) -> {ok, {bool_value, Raw /= 0}} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 187). -spec decode_bytes_at(bitstring(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_bytes_at(Data, Offset) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Length) -> gleam@result:'try'( read_bytes_at(Data, Offset + 32, Length), fun(Bytes) -> {ok, {bytes_value, Bytes}} end ) end ). -file("src/gleeth/ethereum/abi/decode.gleam", 193). -spec decode_string_at(bitstring(), integer()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_string_at(Data, Offset) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Length) -> gleam@result:'try'( read_bytes_at(Data, Offset + 32, Length), fun(Bytes) -> case gleam@bit_array:to_string(Bytes) of {ok, S} -> {ok, {string_value, S}}; {error, _} -> {error, {decode_error, <<"Invalid UTF-8 in string"/utf8>>}} end end ) end ). -file("src/gleeth/ethereum/abi/decode.gleam", 70). -spec decode_static_at( gleeth@ethereum@abi@types:abi_type(), bitstring(), integer() ) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_static_at(T, Data, Offset) -> case T of {uint, Size} -> decode_uint_at(Data, Offset, Size); {int, Size@1} -> decode_int_at(Data, Offset, Size@1); address -> decode_address_at(Data, Offset); bool -> decode_bool_at(Data, Offset); {fixed_bytes, Size@2} -> decode_fixed_bytes_at(Data, Offset, Size@2); {fixed_array, Element_type, Size@3} -> decode_static_fixed_array_at(Element_type, Size@3, Data, Offset); {tuple, Element_types} -> gleam@result:'try'( decode_tuple_at(Element_types, Data, Offset), fun(Values) -> {ok, {tuple_value, Values}} end ); _ -> {error, {decode_error, <<"Expected static type, got dynamic"/utf8>>}} end. -file("src/gleeth/ethereum/abi/decode.gleam", 151). -spec decode_static_fixed_array_at( gleeth@ethereum@abi@types:abi_type(), integer(), bitstring(), integer() ) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_static_fixed_array_at(Element_type, Count, Data, Offset) -> Element_types = gleam@list:repeat(Element_type, Count), gleam@result:'try'( decode_tuple_at(Element_types, Data, Offset), fun(Values) -> {ok, {array_value, Values}} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 37). ?DOC( " Decode a tuple from data starting at a given offset.\n" " The tuple's head starts at `base_offset` within `data`.\n" ). -spec decode_tuple_at( list(gleeth@ethereum@abi@types:abi_type()), bitstring(), integer() ) -> {ok, list(gleeth@ethereum@abi@types:abi_value())} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_tuple_at(Type_list, Data, Base_offset) -> gleam@result:'try'( gleam@list:try_fold( Type_list, {[], Base_offset}, fun(Acc, T) -> {Vals, Head_pos} = Acc, Slot_size = gleeth@ethereum@abi@types:head_size(T), case gleeth@ethereum@abi@types:is_dynamic(T) of false -> gleam@result:'try'( decode_static_at(T, Data, Head_pos), fun(Value) -> {ok, {[Value | Vals], Head_pos + Slot_size}} end ); true -> gleam@result:'try'( read_uint256_at(Data, Head_pos), fun(Offset) -> Abs_offset = Base_offset + Offset, gleam@result:'try'( decode_dynamic_at(T, Data, Abs_offset), fun(Value@1) -> {ok, {[Value@1 | Vals], Head_pos + 32}} end ) end ) end end ), fun(_use0) -> {Values, _} = _use0, {ok, lists:reverse(Values)} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 12). ?DOC( " Decode ABI-encoded data given a list of expected types.\n" " This is the top-level decoder for function return values or event data.\n" ). -spec decode(list(gleeth@ethereum@abi@types:abi_type()), bitstring()) -> {ok, list(gleeth@ethereum@abi@types:abi_value())} | {error, gleeth@ethereum@abi@types:abi_error()}. decode(Type_list, Data) -> decode_tuple_at(Type_list, Data, 0). -file("src/gleeth/ethereum/abi/decode.gleam", 20). ?DOC(" Decode a single value of a known type from ABI-encoded data.\n"). -spec decode_single(gleeth@ethereum@abi@types:abi_type(), bitstring()) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_single(Type_, Data) -> gleam@result:'try'(decode([Type_], Data), fun(Values) -> case Values of [Value] -> {ok, Value}; _ -> {error, {decode_error, <<"Expected exactly one value"/utf8>>}} end end). -file("src/gleeth/ethereum/abi/decode.gleam", 202). -spec decode_dynamic_array_at( gleeth@ethereum@abi@types:abi_type(), bitstring(), integer() ) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_dynamic_array_at(Element_type, Data, Offset) -> gleam@result:'try'( read_uint256_at(Data, Offset), fun(Count) -> Element_types = gleam@list:repeat(Element_type, Count), gleam@result:'try'( decode_tuple_at(Element_types, Data, Offset + 32), fun(Values) -> {ok, {array_value, Values}} end ) end ). -file("src/gleeth/ethereum/abi/decode.gleam", 213). -spec decode_dynamic_fixed_array_at( gleeth@ethereum@abi@types:abi_type(), integer(), bitstring(), integer() ) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_dynamic_fixed_array_at(Element_type, Count, Data, Offset) -> Element_types = gleam@list:repeat(Element_type, Count), gleam@result:'try'( decode_tuple_at(Element_types, Data, Offset), fun(Values) -> {ok, {array_value, Values}} end ). -file("src/gleeth/ethereum/abi/decode.gleam", 167). -spec decode_dynamic_at( gleeth@ethereum@abi@types:abi_type(), bitstring(), integer() ) -> {ok, gleeth@ethereum@abi@types:abi_value()} | {error, gleeth@ethereum@abi@types:abi_error()}. decode_dynamic_at(T, Data, Offset) -> case T of bytes -> decode_bytes_at(Data, Offset); string -> decode_string_at(Data, Offset); {array, Element_type} -> decode_dynamic_array_at(Element_type, Data, Offset); {fixed_array, Element_type@1, Size} -> decode_dynamic_fixed_array_at(Element_type@1, Size, Data, Offset); {tuple, Element_types} -> gleam@result:'try'( decode_tuple_at(Element_types, Data, Offset), fun(Values) -> {ok, {tuple_value, Values}} end ); _ -> {error, {decode_error, <<"Expected dynamic type"/utf8>>}} end.