Current section
Files
Jump to
Current section
Files
src/gleeth@ethereum@abi@decode.erl
-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, <<Byte:8>>} ->
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.