-module(gleeth@wei). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/wei.gleam"). -export([from_int/1, from_ether/1, from_gwei/1, to_int/1, to_ether/1, to_gwei/1]). -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( " Convert between human-readable values (ETH, gwei, integers) and the\n" " `0x`-prefixed hex strings used by the Ethereum JSON-RPC wire format.\n" "\n" " All RPC methods in gleeth accept and return hex strings. This module\n" " bridges the gap so users don't have to construct hex manually.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(hex) = wei.from_ether(\"1.0\")\n" " // hex = \"0xde0b6b3a7640000\"\n" "\n" " let assert Ok(eth) = wei.to_ether(\"0xde0b6b3a7640000\")\n" " // eth = \"1.0\"\n" " ```\n" ). -file("src/gleeth/wei.gleam", 80). ?DOC( " Convert a decimal integer to a hex string.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.from_int(21000) // -> \"0x5208\"\n" " wei.from_int(0) // -> \"0x0\"\n" " ```\n" ). -spec from_int(integer()) -> binary(). from_int(Value) -> case Value of 0 -> <<"0x0"/utf8>>; _ -> <<"0x"/utf8, (string:lowercase(gleam@int:to_base16(Value)))/binary>> end. -file("src/gleeth/wei.gleam", 208). -spec nibble_to_char(integer()) -> binary(). nibble_to_char(N) -> case N of 0 -> <<"0"/utf8>>; 1 -> <<"1"/utf8>>; 2 -> <<"2"/utf8>>; 3 -> <<"3"/utf8>>; 4 -> <<"4"/utf8>>; 5 -> <<"5"/utf8>>; 6 -> <<"6"/utf8>>; 7 -> <<"7"/utf8>>; 8 -> <<"8"/utf8>>; 9 -> <<"9"/utf8>>; 10 -> <<"a"/utf8>>; 11 -> <<"b"/utf8>>; 12 -> <<"c"/utf8>>; 13 -> <<"d"/utf8>>; 14 -> <<"e"/utf8>>; 15 -> <<"f"/utf8>>; _ -> <<"0"/utf8>> end. -file("src/gleeth/wei.gleam", 193). -spec bigint_to_hex_loop(bigi:big_int(), binary()) -> binary(). bigint_to_hex_loop(Value, Acc) -> Zero = bigi_ffi:from(0), Sixteen = bigi_ffi:from(16), case bigi_ffi:compare(Value, Zero) of eq -> Acc; _ -> Remainder = bigi_ffi:remainder(Value, Sixteen), Quotient = bigi_ffi:divide(Value, Sixteen), Nibble@1 = case bigi_ffi:to(Remainder) of {ok, Nibble} -> Nibble; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"gleeth/wei"/utf8>>, function => <<"bigint_to_hex_loop"/utf8>>, line => 201, value => _assert_fail, start => 5930, 'end' => 5976, pattern_start => 5941, pattern_end => 5951}) end, Hex_char = nibble_to_char(Nibble@1), bigint_to_hex_loop(Quotient, <>) end. -file("src/gleeth/wei.gleam", 182). -spec bigint_to_hex(bigi:big_int()) -> binary(). bigint_to_hex(Value) -> Zero = bigi_ffi:from(0), case bigi_ffi:compare(Value, Zero) of eq -> <<"0x0"/utf8>>; _ -> Hex_str = bigint_to_hex_loop(Value, <<""/utf8>>), <<"0x"/utf8, (string:lowercase(Hex_str))/binary>> end. -file("src/gleeth/wei.gleam", 230). -spec power_of_10_string(integer()) -> binary(). power_of_10_string(N) -> <<"1"/utf8, (gleam@string:repeat(<<"0"/utf8>>, N))/binary>>. -file("src/gleeth/wei.gleam", 148). ?DOC( " Parse a decimal string like \"1.5\" or \"100\" into a BigInt representing\n" " wei (multiplied by 10^decimals).\n" ). -spec parse_decimal_to_bigint(binary(), integer()) -> {ok, bigi:big_int()} | {error, binary()}. parse_decimal_to_bigint(Amount, Decimals) -> case gleam@string:split(Amount, <<"."/utf8>>) of [Whole] -> gleam@result:'try'( begin _pipe = bigi_ffi:from_string(Whole), gleam@result:map_error( _pipe, fun(_) -> <<"Invalid number: "/utf8, Amount/binary>> end ) end, fun(Whole_big) -> Multiplier@1 = case bigi_ffi:from_string( power_of_10_string(Decimals) ) of {ok, Multiplier} -> Multiplier; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"gleeth/wei"/utf8>>, function => <<"parse_decimal_to_bigint"/utf8>>, line => 159, value => _assert_fail, start => 4642, 'end' => 4716, pattern_start => 4653, pattern_end => 4667}) end, {ok, bigi_ffi:multiply(Whole_big, Multiplier@1)} end ); [Whole@1, Frac] -> Frac_len = string:length(Frac), case Frac_len > Decimals of true -> {error, <<<<"Too many decimal places (max "/utf8, (erlang:integer_to_binary(Decimals))/binary>>/binary, ")"/utf8>>}; false -> Padded_frac = <>, Decimals - Frac_len))/binary>>, Combined = <>, _pipe@1 = bigi_ffi:from_string(Combined), gleam@result:map_error( _pipe@1, fun(_) -> <<"Invalid number: "/utf8, Amount/binary>> end ) end; _ -> {error, <<"Invalid decimal format: "/utf8, Amount/binary>>} end. -file("src/gleeth/wei.gleam", 110). ?DOC( " Parse a decimal string (possibly with fractional part) and multiply by\n" " 10^decimals to get the wei value as a BigInt, then convert to hex.\n" ). -spec decimal_to_wei(binary(), integer()) -> {ok, binary()} | {error, binary()}. decimal_to_wei(Amount, Decimals) -> Trimmed = gleam@string:trim(Amount), case Trimmed of <<""/utf8>> -> {error, <<"Empty amount"/utf8>>}; _ -> gleam@result:'try'( parse_decimal_to_bigint(Trimmed, Decimals), fun(Wei) -> Zero = bigi_ffi:from(0), case bigi_ffi:compare(Wei, Zero) of lt -> {error, <<"Negative amounts not supported"/utf8>>}; _ -> {ok, bigint_to_hex(Wei)} end end ) end. -file("src/gleeth/wei.gleam", 33). ?DOC( " Convert an ether amount string to a wei hex string.\n" " Handles integers (\"1\", \"100\") and decimals (\"1.5\", \"0.001\").\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.from_ether(\"1.0\") // -> Ok(\"0xde0b6b3a7640000\")\n" " wei.from_ether(\"0.5\") // -> Ok(\"0x6f05b59d3b20000\")\n" " wei.from_ether(\"0\") // -> Ok(\"0x0\")\n" " ```\n" ). -spec from_ether(binary()) -> {ok, binary()} | {error, binary()}. from_ether(Ether) -> decimal_to_wei(Ether, 18). -file("src/gleeth/wei.gleam", 45). ?DOC( " Convert a gwei amount string to a wei hex string.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.from_gwei(\"1.0\") // -> Ok(\"0x3b9aca00\")\n" " wei.from_gwei(\"20\") // -> Ok(\"0x4a817c800\")\n" " ```\n" ). -spec from_gwei(binary()) -> {ok, binary()} | {error, binary()}. from_gwei(Gwei) -> decimal_to_wei(Gwei, 9). -file("src/gleeth/wei.gleam", 234). -spec strip_0x(binary()) -> binary(). strip_0x(S) -> case gleam_stdlib:string_starts_with(S, <<"0x"/utf8>>) of true -> gleam@string:drop_start(S, 2); false -> S end. -file("src/gleeth/wei.gleam", 94). ?DOC( " Convert a hex string to a decimal integer.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.to_int(\"0x5208\") // -> Ok(21000)\n" " ```\n" ). -spec to_int(binary()) -> {ok, integer()} | {error, binary()}. to_int(Hex_string) -> Clean = strip_0x(Hex_string), case Clean of <<""/utf8>> -> {ok, 0}; _ -> _pipe = gleam@int:base_parse(Clean, 16), gleam@result:map_error( _pipe, fun(_) -> <<"Invalid hex: "/utf8, Hex_string/binary>> end ) end. -file("src/gleeth/wei.gleam", 241). -spec trim_trailing_zeros(binary()) -> binary(). trim_trailing_zeros(S) -> case gleam_stdlib:string_ends_with(S, <<"0"/utf8>>) of true -> Trimmed = gleam@string:drop_end(S, 1), case Trimmed of <<""/utf8>> -> <<"0"/utf8>>; _ -> trim_trailing_zeros(Trimmed) end; false -> case S of <<""/utf8>> -> <<"0"/utf8>>; _ -> S end end. -file("src/gleeth/wei.gleam", 127). ?DOC( " Convert wei BigInt back to a decimal string with the given number of\n" " decimal places.\n" ). -spec wei_to_decimal(binary(), integer()) -> {ok, binary()} | {error, binary()}. wei_to_decimal(Hex_string, Decimals) -> gleam@result:'try'( begin _pipe = gleeth@utils@hex:hex_to_bigint(Hex_string), gleam@result:map_error( _pipe, fun(_) -> <<"Invalid hex: "/utf8, Hex_string/binary>> end ) end, fun(Wei) -> Divisor_str = power_of_10_string(Decimals), Divisor@1 = case bigi_ffi:from_string(Divisor_str) of {ok, Divisor} -> Divisor; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"gleeth/wei"/utf8>>, function => <<"wei_to_decimal"/utf8>>, line => 133, value => _assert_fail, start => 3658, 'end' => 3712, pattern_start => 3669, pattern_end => 3680}) end, Whole = bigi_ffi:divide(Wei, Divisor@1), Remainder = bigi_ffi:remainder(Wei, Divisor@1), Whole_str = erlang:integer_to_binary(Whole), Remainder_str = erlang:integer_to_binary(Remainder), Padded = <<(gleam@string:repeat( <<"0"/utf8>>, Decimals - string:length(Remainder_str) ))/binary, Remainder_str/binary>>, Trimmed = trim_trailing_zeros(Padded), {ok, <<<>/binary, Trimmed/binary>>} end ). -file("src/gleeth/wei.gleam", 57). ?DOC( " Convert a wei hex string to an ether decimal string.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.to_ether(\"0xde0b6b3a7640000\") // -> Ok(\"1.0\")\n" " wei.to_ether(\"0x0\") // -> Ok(\"0.0\")\n" " ```\n" ). -spec to_ether(binary()) -> {ok, binary()} | {error, binary()}. to_ether(Wei_hex) -> wei_to_decimal(Wei_hex, 18). -file("src/gleeth/wei.gleam", 68). ?DOC( " Convert a wei hex string to a gwei decimal string.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " wei.to_gwei(\"0x3b9aca00\") // -> Ok(\"1.0\")\n" " ```\n" ). -spec to_gwei(binary()) -> {ok, binary()} | {error, binary()}. to_gwei(Wei_hex) -> wei_to_decimal(Wei_hex, 9).