-module(gleeth@commands@parallel_balance). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/commands/parallel_balance.gleam"). -export([execute_parallel/3]). -export_type([balance_result/0, balance_summary/0]). -type balance_result() :: {balance_success, binary(), binary(), float()} | {balance_error, binary(), binary()}. -type balance_summary() :: {balance_summary, integer(), integer(), integer(), float(), float()}. -file("src/gleeth/commands/parallel_balance.gleam", 58). -spec get_all_addresses(list(binary()), gleam@option:option(binary())) -> {ok, list(binary())} | {error, gleeth@rpc@types:gleeth_error()}. get_all_addresses(Direct_addresses, File) -> case File of {some, Filename} -> gleam@result:'try'( gleeth@utils@file:read_addresses_from_file(Filename), fun(File_addresses) -> {ok, lists:append(Direct_addresses, File_addresses)} end ); none -> {ok, Direct_addresses} end. -file("src/gleeth/commands/parallel_balance.gleam", 103). -spec collect_results( gleam@erlang@process:subject(balance_result()), integer(), list(balance_result()) ) -> list(balance_result()). collect_results(Subject, Remaining, Acc) -> case Remaining of 0 -> lists:reverse(Acc); N -> case gleam@erlang@process:'receive'(Subject, 30000) of {ok, Result} -> collect_results(Subject, N - 1, [Result | Acc]); {error, nil} -> lists:reverse(Acc) end end. -file("src/gleeth/commands/parallel_balance.gleam", 132). -spec error_to_string(gleeth@rpc@types:gleeth_error()) -> binary(). error_to_string(Error) -> gleeth@rpc@types:error_to_string(Error). -file("src/gleeth/commands/parallel_balance.gleam", 120). -spec check_single_balance(gleeth@provider:provider(), binary()) -> balance_result(). check_single_balance(Provider, Address) -> case gleeth@rpc@methods:get_balance(Provider, Address) of {ok, Balance_wei} -> case gleeth@utils@hex:wei_to_ether(Balance_wei) of {ok, Ether_amount} -> {balance_success, Address, Balance_wei, Ether_amount}; {error, _} -> {balance_error, Address, <<"Failed to convert Wei to Ether"/utf8>>} end; {error, Error} -> {balance_error, Address, error_to_string(Error)} end. -file("src/gleeth/commands/parallel_balance.gleam", 83). -spec check_batch_concurrently(gleeth@provider:provider(), list(binary())) -> list(balance_result()). check_batch_concurrently(Provider, Addresses) -> Subject = gleam@erlang@process:new_subject(), Batch_size = erlang:length(Addresses), gleam@list:each( Addresses, fun(Address) -> proc_lib:spawn_link( fun() -> Result = check_single_balance(Provider, Address), gleam@erlang@process:send(Subject, Result) end ) end ), collect_results(Subject, Batch_size, []). -file("src/gleeth/commands/parallel_balance.gleam", 73). -spec check_balances_concurrently(gleeth@provider:provider(), list(binary())) -> list(balance_result()). check_balances_concurrently(Provider, Addresses) -> _pipe = Addresses, _pipe@1 = gleam@list:sized_chunk(_pipe, 10), gleam@list:flat_map( _pipe@1, fun(Batch) -> check_batch_concurrently(Provider, Batch) end ). -file("src/gleeth/commands/parallel_balance.gleam", 153). -spec print_table_header() -> nil. print_table_header() -> gleam_stdlib:println( <<"┌──────────────────────────────────────────────┬─────────────────┬─────────────┐"/utf8>> ), gleam_stdlib:println( <<"│ Address │ Balance (ETH) │ Status │"/utf8>> ). -file("src/gleeth/commands/parallel_balance.gleam", 163). -spec print_table_separator() -> nil. print_table_separator() -> gleam_stdlib:println( <<"├──────────────────────────────────────────────┼─────────────────┼─────────────┤"/utf8>> ). -file("src/gleeth/commands/parallel_balance.gleam", 211). -spec float_to_string_rounded(float(), integer()) -> binary(). float_to_string_rounded(F, _) -> gleam_stdlib:float_to_string(F). -file("src/gleeth/commands/parallel_balance.gleam", 201). -spec format_ether(float()) -> binary(). format_ether(Ether) -> case Ether of E when E > 1000.0 -> <<(float_to_string_rounded(E, 3))/binary, " ETH"/utf8>>; E@1 when E@1 > 1.0 -> <<(float_to_string_rounded(E@1, 6))/binary, " ETH"/utf8>>; E@2 when E@2 > 0.001 -> <<(float_to_string_rounded(E@2, 9))/binary, " ETH"/utf8>>; E@3 -> <<(float_to_string_rounded(E@3, 12))/binary, " ETH"/utf8>> end. -file("src/gleeth/commands/parallel_balance.gleam", 234). -spec truncate_string(binary(), integer()) -> binary(). truncate_string(Str, Max_length) -> case string:length(Str) =< Max_length of true -> Str; false -> <<(gleam@string:slice(Str, 0, Max_length - 3))/binary, "..."/utf8>> end. -file("src/gleeth/commands/parallel_balance.gleam", 216). -spec pad_right(binary(), integer()) -> binary(). pad_right(Str, Width) -> Current_length = string:length(Str), case Current_length >= Width of true -> truncate_string(Str, Width); false -> <>, Width - Current_length))/binary>> end. -file("src/gleeth/commands/parallel_balance.gleam", 225). -spec pad_left(binary(), integer()) -> binary(). pad_left(Str, Width) -> Current_length = string:length(Str), case Current_length >= Width of true -> truncate_string(Str, Width); false -> <<(gleam@string:repeat(<<" "/utf8>>, Width - Current_length))/binary, Str/binary>> end. -file("src/gleeth/commands/parallel_balance.gleam", 170). -spec print_balance_row(balance_result()) -> nil. print_balance_row(Result) -> case Result of {balance_success, Address, _, Ether} -> Formatted_address = pad_right(Address, 44), Formatted_balance = pad_left(format_ether(Ether), 15), gleam_stdlib:println( <<<<<<<<"│ "/utf8, Formatted_address/binary>>/binary, " │ "/utf8>>/binary, Formatted_balance/binary>>/binary, " │ ✓ │"/utf8>> ); {balance_error, Address@1, Error} -> Formatted_address@1 = pad_right(Address@1, 44), Formatted_error = pad_left(<<"ERROR"/utf8>>, 15), gleam_stdlib:println( <<<<<<<<"│ "/utf8, Formatted_address@1/binary>>/binary, " │ "/utf8>>/binary, Formatted_error/binary>>/binary, " │ ✗ │"/utf8>> ), gleam_stdlib:println( <<<<"│ Error: "/utf8, (pad_right(truncate_string(Error, 60), 62))/binary>>/binary, " │"/utf8>> ) end. -file("src/gleeth/commands/parallel_balance.gleam", 242). -spec calculate_summary(list(balance_result())) -> balance_summary(). calculate_summary(Results) -> Total_addresses = erlang:length(Results), Successful_results = gleam@list:filter( Results, fun(Result) -> case Result of {balance_success, _, _, _} -> true; {balance_error, _, _} -> false end end ), Successful = erlang:length(Successful_results), Failed = Total_addresses - Successful, Total_ether = gleam@list:fold( Successful_results, +0.0, fun(Acc, Result@1) -> case Result@1 of {balance_success, _, _, Ether} -> Acc + Ether; {balance_error, _, _} -> Acc end end ), Average_ether = case Successful of 0 -> +0.0; _ -> case erlang:float(Successful) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> Total_ether / Gleam@denominator end end, {balance_summary, Total_addresses, Successful, Failed, Total_ether, Average_ether}. -file("src/gleeth/commands/parallel_balance.gleam", 277). -spec print_summary(balance_summary()) -> nil. print_summary(Summary) -> gleam_stdlib:println( <<"└──────────────────────────────────────────────┴─────────────────┴─────────────┘"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Summary:"/utf8>>), gleam_stdlib:println( <<" Total addresses: "/utf8, (erlang:integer_to_binary(erlang:element(2, Summary)))/binary>> ), gleam_stdlib:println( <<" Successful: "/utf8, (erlang:integer_to_binary(erlang:element(3, Summary)))/binary>> ), gleam_stdlib:println( <<" Failed: "/utf8, (erlang:integer_to_binary(erlang:element(4, Summary)))/binary>> ), case erlang:element(3, Summary) > 0 of true -> gleam_stdlib:println( <<" Total ETH: "/utf8, (format_ether(erlang:element(5, Summary)))/binary>> ), gleam_stdlib:println( <<" Average ETH: "/utf8, (format_ether(erlang:element(6, Summary)))/binary>> ); false -> nil end. -file("src/gleeth/commands/parallel_balance.gleam", 137). -spec display_results(list(balance_result())) -> nil. display_results(Results) -> Summary = calculate_summary(Results), print_table_header(), print_table_separator(), gleam@list:each(Results, fun print_balance_row/1), print_table_separator(), print_summary(Summary). -file("src/gleeth/commands/parallel_balance.gleam", 35). -spec execute_parallel( gleeth@provider:provider(), list(binary()), gleam@option:option(binary()) ) -> {ok, nil} | {error, gleeth@rpc@types:gleeth_error()}. execute_parallel(Provider, Addresses, File) -> gleam@result:'try'( get_all_addresses(Addresses, File), fun(Final_addresses) -> case Final_addresses of [] -> {error, {config_error, <<"No addresses to check"/utf8>>}}; Addrs -> gleam_stdlib:println( <<<<"Checking "/utf8, (erlang:integer_to_binary(erlang:length(Addrs)))/binary>>/binary, " addresses..."/utf8>> ), gleam_stdlib:println(<<""/utf8>>), Results = check_balances_concurrently(Provider, Addrs), display_results(Results), {ok, nil} end end ).