-module(gleeth@utils@hex). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/utils/hex.gleam"). -export([hex_to_bigint/1, hex_to_int/1, wei_to_ether/1, wei_to_gwei/1, format_wei_to_ether/1, format_wei_to_gwei/1, format_block_number/1, is_valid_hex/1, decode/1, encode/1, strip_prefix/1, ensure_prefix/1, normalize/1, from_int/1, to_int/1, is_valid_hex_chars/1, format_with_decimal/1, pad_left/2, validate_length/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/utils/hex.gleam", 30). -spec char_to_hex_value(binary()) -> {ok, integer()} | {error, nil}. char_to_hex_value(Char) -> case Char of <<"0"/utf8>> -> {ok, 0}; <<"1"/utf8>> -> {ok, 1}; <<"2"/utf8>> -> {ok, 2}; <<"3"/utf8>> -> {ok, 3}; <<"4"/utf8>> -> {ok, 4}; <<"5"/utf8>> -> {ok, 5}; <<"6"/utf8>> -> {ok, 6}; <<"7"/utf8>> -> {ok, 7}; <<"8"/utf8>> -> {ok, 8}; <<"9"/utf8>> -> {ok, 9}; <<"a"/utf8>> -> {ok, 10}; <<"A"/utf8>> -> {ok, 10}; <<"b"/utf8>> -> {ok, 11}; <<"B"/utf8>> -> {ok, 11}; <<"c"/utf8>> -> {ok, 12}; <<"C"/utf8>> -> {ok, 12}; <<"d"/utf8>> -> {ok, 13}; <<"D"/utf8>> -> {ok, 13}; <<"e"/utf8>> -> {ok, 14}; <<"E"/utf8>> -> {ok, 14}; <<"f"/utf8>> -> {ok, 15}; <<"F"/utf8>> -> {ok, 15}; _ -> {error, nil} end. -file("src/gleeth/utils/hex.gleam", 23). -spec hex_chars_to_bigint(binary()) -> {ok, bigi:big_int()} | {error, nil}. hex_chars_to_bigint(Hex) -> Chars = gleam@string:to_graphemes(Hex), gleam@result:'try'( gleam@list:try_map(Chars, fun char_to_hex_value/1), fun(Digits) -> bigi:undigits(Digits, 16) end ). -file("src/gleeth/utils/hex.gleam", 10). -spec hex_to_bigint(binary()) -> {ok, bigi:big_int()} | {error, nil}. hex_to_bigint(Hex_string) -> Clean_hex = case gleam_stdlib:string_starts_with(Hex_string, <<"0x"/utf8>>) of true -> gleam@string:drop_start(Hex_string, 2); false -> Hex_string end, case Clean_hex of <<""/utf8>> -> {ok, bigi_ffi:from(0)}; _ -> hex_chars_to_bigint(Clean_hex) end. -file("src/gleeth/utils/hex.gleam", 53). -spec hex_to_int(binary()) -> {ok, integer()} | {error, nil}. hex_to_int(Hex_string) -> gleam@result:'try'( hex_to_bigint(Hex_string), fun(Bigint) -> bigi_ffi:to(Bigint) end ). -file("src/gleeth/utils/hex.gleam", 99). -spec string_division(binary(), integer(), float()) -> {ok, float()} | {error, nil}. string_division(Wei_str, Decimals, Divisor) -> Wei_len = string:length(Wei_str), case Wei_len of Len when Len =< Decimals -> case gleam_stdlib:parse_int(Wei_str) of {ok, Wei_int} -> {ok, case Divisor of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> erlang:float(Wei_int) / Gleam@denominator end}; {error, _} -> {error, nil} end; Len@1 -> Whole_part = gleam@string:drop_end(Wei_str, Decimals), Frac_part = gleam@string:drop_start(Wei_str, Len@1 - Decimals), case gleam_stdlib:parse_int(Whole_part) of {ok, Whole_int} -> Whole_float = erlang:float(Whole_int), case gleam_stdlib:parse_int(Frac_part) of {ok, Frac_int} -> {ok, Whole_float + (case Divisor of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator@1 -> erlang:float( Frac_int ) / Gleam@denominator@1 end)}; {error, _} -> {ok, Whole_float} end; {error, _} -> {error, nil} end end. -file("src/gleeth/utils/hex.gleam", 130). -spec wei_to_ether_string_division(binary()) -> {ok, float()} | {error, nil}. wei_to_ether_string_division(Wei_str) -> string_division(Wei_str, 18, 1000000000000000000.0). -file("src/gleeth/utils/hex.gleam", 59). -spec wei_to_ether(binary()) -> {ok, float()} | {error, nil}. wei_to_ether(Wei_hex) -> gleam@result:'try'( hex_to_bigint(Wei_hex), fun(Wei_bigint) -> Wei_str = erlang:integer_to_binary(Wei_bigint), case gleam_stdlib:parse_int(Wei_str) of {ok, Wei_int} -> Wei_float = erlang:float(Wei_int), Ether = Wei_float / 1000000000000000000.0, {ok, Ether}; {error, _} -> wei_to_ether_string_division(Wei_str) end end ). -file("src/gleeth/utils/hex.gleam", 134). -spec wei_to_gwei_string_division(binary()) -> {ok, float()} | {error, nil}. wei_to_gwei_string_division(Wei_str) -> string_division(Wei_str, 9, 1000000000.0). -file("src/gleeth/utils/hex.gleam", 78). -spec wei_to_gwei(binary()) -> {ok, float()} | {error, nil}. wei_to_gwei(Wei_hex) -> gleam@result:'try'( hex_to_bigint(Wei_hex), fun(Wei_bigint) -> Wei_str = erlang:integer_to_binary(Wei_bigint), case gleam_stdlib:parse_int(Wei_str) of {ok, Wei_int} -> Wei_float = erlang:float(Wei_int), Gwei = Wei_float / 1000000000.0, {ok, Gwei}; {error, _} -> wei_to_gwei_string_division(Wei_str) end end ). -file("src/gleeth/utils/hex.gleam", 139). -spec format_wei_to_ether(binary()) -> binary(). format_wei_to_ether(Wei_hex) -> case wei_to_ether(Wei_hex) of {ok, Ether} -> Ether_str = gleam_stdlib:float_to_string(Ether), case Ether > 0.001 of true -> <>; false -> <<<<<>/binary, Wei_hex/binary>>/binary, " Wei)"/utf8>> end; {error, _} -> <> end. -file("src/gleeth/utils/hex.gleam", 156). -spec format_wei_to_gwei(binary()) -> binary(). format_wei_to_gwei(Wei_hex) -> case wei_to_gwei(Wei_hex) of {ok, Gwei} -> Gwei_str = gleam_stdlib:float_to_string(Gwei), <>; {error, _} -> <> end. -file("src/gleeth/utils/hex.gleam", 167). -spec format_block_number(binary()) -> binary(). format_block_number(Block_hex) -> case hex_to_bigint(Block_hex) of {ok, Block_bigint} -> erlang:integer_to_binary(Block_bigint); {error, _} -> Block_hex end. -file("src/gleeth/utils/hex.gleam", 175). -spec is_valid_hex(binary()) -> boolean(). is_valid_hex(Hex_string) -> case hex_to_bigint(Hex_string) of {ok, _} -> true; {error, _} -> false end. -file("src/gleeth/utils/hex.gleam", 206). -spec decode_hex_chars_to_bytes(list(binary()), list(integer())) -> {ok, list(integer())} | {error, binary()}. decode_hex_chars_to_bytes(Chars, Acc) -> case Chars of [] -> {ok, lists:reverse(Acc)}; [High, Low | Rest] -> gleam@result:'try'( begin _pipe = char_to_hex_value(High), gleam@result:map_error( _pipe, fun(_) -> <<"Invalid hex character: "/utf8, High/binary>> end ) end, fun(High_val) -> gleam@result:'try'( begin _pipe@1 = char_to_hex_value(Low), gleam@result:map_error( _pipe@1, fun(_) -> <<"Invalid hex character: "/utf8, Low/binary>> end ) end, fun(Low_val) -> Byte_val = (High_val * 16) + Low_val, decode_hex_chars_to_bytes(Rest, [Byte_val | Acc]) end ) end ); [_] -> {error, <<"Hex string must have an even number of characters"/utf8>>} end. -file("src/gleeth/utils/hex.gleam", 196). -spec decode_hex_pairs(binary()) -> {ok, bitstring()} | {error, binary()}. decode_hex_pairs(Hex) -> Chars = gleam@string:to_graphemes(Hex), gleam@result:'try'( decode_hex_chars_to_bytes(Chars, []), fun(Bytes) -> Bit_pattern = gleam@list:fold( Bytes, <<>>, fun(Acc, Byte) -> <> end ), {ok, Bit_pattern} end ). -file("src/gleeth/utils/hex.gleam", 183). -spec decode(binary()) -> {ok, bitstring()} | {error, binary()}. decode(Hex_string) -> Clean_hex = case gleam_stdlib:string_starts_with(Hex_string, <<"0x"/utf8>>) of true -> gleam@string:drop_start(Hex_string, 2); false -> Hex_string end, case string:length(Clean_hex) rem 2 of 0 -> decode_hex_pairs(Clean_hex); _ -> {error, <<"Hex string must have an even number of characters"/utf8>>} end. -file("src/gleeth/utils/hex.gleam", 229). -spec encode(bitstring()) -> binary(). encode(Data) -> <<"0x"/utf8, (begin _pipe = gleam_stdlib:base16_encode(Data), string:lowercase(_pipe) end)/binary>>. -file("src/gleeth/utils/hex.gleam", 238). ?DOC(" Remove 0x prefix from hex string if present\n"). -spec strip_prefix(binary()) -> binary(). strip_prefix(Hex_string) -> case gleam_stdlib:string_starts_with(Hex_string, <<"0x"/utf8>>) of true -> gleam@string:drop_start(Hex_string, 2); false -> Hex_string end. -file("src/gleeth/utils/hex.gleam", 246). ?DOC(" Add 0x prefix to hex string if not present\n"). -spec ensure_prefix(binary()) -> binary(). ensure_prefix(Hex_string) -> case gleam_stdlib:string_starts_with(Hex_string, <<"0x"/utf8>>) of true -> Hex_string; false -> <<"0x"/utf8, Hex_string/binary>> end. -file("src/gleeth/utils/hex.gleam", 254). ?DOC(" Normalize hex string to lowercase with 0x prefix\n"). -spec normalize(binary()) -> binary(). normalize(Hex_string) -> Clean = strip_prefix(Hex_string), <<"0x"/utf8, (string:lowercase(Clean))/binary>>. -file("src/gleeth/utils/hex.gleam", 260). ?DOC(" Convert integer to hex string with 0x prefix\n"). -spec from_int(integer()) -> binary(). from_int(Value) -> <<"0x"/utf8, (begin _pipe = gleam@int:to_base16(Value), string:lowercase(_pipe) end)/binary>>. -file("src/gleeth/utils/hex.gleam", 265). ?DOC(" Parse hex string to integer (with or without 0x prefix)\n"). -spec to_int(binary()) -> {ok, integer()} | {error, nil}. to_int(Hex_string) -> gleam@result:'try'( hex_to_bigint(Hex_string), fun(Bigint) -> bigi_ffi:to(Bigint) end ). -file("src/gleeth/utils/hex.gleam", 277). ?DOC(" Check if a single character is a valid hex digit\n"). -spec is_hex_char(binary()) -> boolean(). is_hex_char(Char) -> case Char of <<"0"/utf8>> -> true; <<"1"/utf8>> -> true; <<"2"/utf8>> -> true; <<"3"/utf8>> -> true; <<"4"/utf8>> -> true; <<"5"/utf8>> -> true; <<"6"/utf8>> -> true; <<"7"/utf8>> -> true; <<"8"/utf8>> -> true; <<"9"/utf8>> -> true; <<"a"/utf8>> -> true; <<"b"/utf8>> -> true; <<"c"/utf8>> -> true; <<"d"/utf8>> -> true; <<"e"/utf8>> -> true; <<"f"/utf8>> -> true; <<"A"/utf8>> -> true; <<"B"/utf8>> -> true; <<"C"/utf8>> -> true; <<"D"/utf8>> -> true; <<"E"/utf8>> -> true; <<"F"/utf8>> -> true; _ -> false end. -file("src/gleeth/utils/hex.gleam", 271). ?DOC(" Validate that a string contains only valid hex characters (after stripping 0x)\n"). -spec is_valid_hex_chars(binary()) -> boolean(). is_valid_hex_chars(Hex_string) -> Clean = strip_prefix(Hex_string), _pipe = gleam@string:to_graphemes(Clean), gleam@list:all(_pipe, fun is_hex_char/1). -file("src/gleeth/utils/hex.gleam", 287). ?DOC(" Format a hex value with decimal equivalent for display\n"). -spec format_with_decimal(binary()) -> binary(). format_with_decimal(Hex_string) -> case to_int(Hex_string) of {ok, Decimal_value} -> <<<<<<(erlang:integer_to_binary(Decimal_value))/binary, " ("/utf8>>/binary, (normalize(Hex_string))/binary>>/binary, ")"/utf8>>; {error, _} -> normalize(Hex_string) end. -file("src/gleeth/utils/hex.gleam", 296). ?DOC(" Pad hex string to specified length (without 0x prefix)\n"). -spec pad_left(binary(), integer()) -> binary(). pad_left(Hex_string, Target_length) -> Clean = strip_prefix(Hex_string), Current_length = string:length(Clean), case Current_length >= Target_length of true -> Clean; false -> Padding_needed = Target_length - Current_length, Padding = gleam@string:repeat(<<"0"/utf8>>, Padding_needed), <> end. -file("src/gleeth/utils/hex.gleam", 310). ?DOC(" Validate hex string has correct length for specific data types\n"). -spec validate_length(binary(), integer()) -> {ok, binary()} | {error, binary()}. validate_length(Hex_string, Expected_bytes) -> Clean = strip_prefix(Hex_string), Expected_chars = Expected_bytes * 2, case string:length(Clean) of Actual_chars when Actual_chars =:= Expected_chars -> {ok, Clean}; Actual_chars@1 -> {error, <<<<<<"Expected "/utf8, (erlang:integer_to_binary(Expected_chars))/binary>>/binary, " hex characters, got "/utf8>>/binary, (erlang:integer_to_binary(Actual_chars@1))/binary>>} end.