Packages

Ethereum library for Gleam - JSON-RPC client, transaction signing, ABI encoding, and wallet management on the BEAM

Current section

Files

Jump to
gleeth src gleeth@commands@call.erl
Raw

src/gleeth@commands@call.erl

-module(gleeth@commands@call).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeth/commands/call.gleam").
-export([execute/5]).
-file("src/gleeth/commands/call.gleam", 60).
-spec parse_parameters(list(binary())) -> {ok,
list({gleeth@ethereum@abi@types:abi_type(),
gleeth@ethereum@abi@types:abi_value()})} |
{error, gleeth@rpc@types:gleeth_error()}.
parse_parameters(Param_strings) ->
gleam@list:try_map(
Param_strings,
fun gleeth@ethereum@contract:parse_parameter/1
).
-file("src/gleeth/commands/call.gleam", 200).
-spec abi_error_message(gleeth@ethereum@abi@types:abi_error()) -> binary().
abi_error_message(Err) ->
case Err of
{encode_error, Msg} ->
Msg;
{decode_error, Msg@1} ->
Msg@1;
{type_parse_error, Msg@2} ->
Msg@2;
{invalid_abi_json, Msg@3} ->
Msg@3
end.
-file("src/gleeth/commands/call.gleam", 233).
-spec decode_uint256(binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_uint256(Hex_data) ->
case string:length(Hex_data) >= 64 of
true ->
Value_hex = gleam@string:slice(Hex_data, 0, 64),
case gleeth@utils@hex:hex_to_int(Value_hex) of
{ok, Int_value} ->
{ok,
erlang:list_to_binary(
[erlang:integer_to_binary(Int_value),
<<" (0x"/utf8>>,
Value_hex,
<<")"/utf8>>]
)};
{error, _} ->
{ok, <<"0x"/utf8, Value_hex/binary>>}
end;
false ->
{error, {parse_error, <<"Response too short for uint256"/utf8>>}}
end.
-file("src/gleeth/commands/call.gleam", 247).
-spec decode_address(binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_address(Hex_data) ->
case string:length(Hex_data) >= 64 of
true ->
Address_hex = gleam@string:slice(Hex_data, 24, 40),
{ok, <<"0x"/utf8, Address_hex/binary>>};
false ->
{error, {parse_error, <<"Response too short for address"/utf8>>}}
end.
-file("src/gleeth/commands/call.gleam", 257).
-spec decode_bool(binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_bool(Hex_data) ->
case string:length(Hex_data) >= 64 of
true ->
Value_hex = gleam@string:slice(Hex_data, 63, 1),
case Value_hex of
<<"0"/utf8>> ->
{ok, <<"false"/utf8>>};
<<"1"/utf8>> ->
{ok, <<"true"/utf8>>};
_ ->
{ok,
<<"0x"/utf8,
(gleam@string:slice(Hex_data, 0, 64))/binary>>}
end;
false ->
{error, {parse_error, <<"Response too short for boolean"/utf8>>}}
end.
-file("src/gleeth/commands/call.gleam", 271).
-spec decode_string_abi(binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_string_abi(Hex_data) ->
case string:length(Hex_data) >= 192 of
true ->
Length_hex = gleam@string:slice(Hex_data, 64, 64),
case gleeth@utils@hex:hex_to_int(Length_hex) of
{ok, Length} ->
Data_hex = gleam@string:slice(Hex_data, 128, Length * 2),
case gleeth@utils@hex:decode(<<"0x"/utf8, Data_hex/binary>>) of
{ok, Bytes} ->
case gleam@bit_array:to_string(Bytes) of
{ok, S} ->
{ok,
<<<<"\""/utf8, S/binary>>/binary,
"\""/utf8>>};
{error, _} ->
{ok,
<<<<"0x"/utf8, Data_hex/binary>>/binary,
" (non-UTF-8)"/utf8>>}
end;
{error, _} ->
{ok,
<<"0x"/utf8,
(gleam@string:slice(Hex_data, 0, 64))/binary>>}
end;
{error, _} ->
{ok,
<<"0x"/utf8,
(gleam@string:slice(Hex_data, 0, 64))/binary>>}
end;
false ->
case string:length(Hex_data) >= 64 of
true ->
{ok,
<<"0x"/utf8,
(gleam@string:slice(Hex_data, 0, 64))/binary>>};
false ->
{error,
{parse_error, <<"Response too short for string"/utf8>>}}
end
end.
-file("src/gleeth/commands/call.gleam", 303).
-spec decode_reserves(binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_reserves(Hex_data) ->
case string:length(Hex_data) >= 192 of
true ->
Reserve0_hex = gleam@string:slice(Hex_data, 0, 64),
Reserve1_hex = gleam@string:slice(Hex_data, 64, 64),
Timestamp_hex = gleam@string:slice(Hex_data, 128, 64),
case {gleeth@utils@hex:hex_to_int(Reserve0_hex),
gleeth@utils@hex:hex_to_int(Reserve1_hex),
gleeth@utils@hex:hex_to_int(Timestamp_hex)} of
{{ok, R0}, {ok, R1}, {ok, Ts}} ->
{ok,
<<<<<<<<<<"Reserve0: "/utf8,
(erlang:integer_to_binary(R0))/binary>>/binary,
", Reserve1: "/utf8>>/binary,
(erlang:integer_to_binary(R1))/binary>>/binary,
", Timestamp: "/utf8>>/binary,
(erlang:integer_to_binary(Ts))/binary>>};
{_, _, _} ->
{ok, <<"0x"/utf8, Hex_data/binary>>}
end;
false ->
{error, {parse_error, <<"Response too short for reserves"/utf8>>}}
end.
-file("src/gleeth/commands/call.gleam", 213).
-spec decode_response(binary(), binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
decode_response(Function_name, Response) ->
Clean_response = gleeth@utils@hex:strip_prefix(Response),
case Function_name of
<<"balanceOf"/utf8>> ->
decode_uint256(Clean_response);
<<"totalSupply"/utf8>> ->
decode_uint256(Clean_response);
<<"allowance"/utf8>> ->
decode_uint256(Clean_response);
<<"decimals"/utf8>> ->
decode_uint256(Clean_response);
<<"owner"/utf8>> ->
decode_address(Clean_response);
<<"token0"/utf8>> ->
decode_address(Clean_response);
<<"token1"/utf8>> ->
decode_address(Clean_response);
<<"name"/utf8>> ->
decode_string_abi(Clean_response);
<<"symbol"/utf8>> ->
decode_string_abi(Clean_response);
<<"approve"/utf8>> ->
decode_bool(Clean_response);
<<"transfer"/utf8>> ->
decode_bool(Clean_response);
<<"getReserves"/utf8>> ->
decode_reserves(Clean_response);
_ ->
{error,
{parse_error,
<<"Unknown return type for function: "/utf8,
Function_name/binary>>}}
end.
-file("src/gleeth/commands/call.gleam", 172).
-spec format_single_value(
gleeth@ethereum@abi@types:abi_type(),
gleeth@ethereum@abi@types:abi_value()
) -> binary().
format_single_value(T, V) ->
case {T, V} of
{{uint, _}, {uint_value, N}} ->
erlang:integer_to_binary(N);
{{int, _}, {int_value, N@1}} ->
erlang:integer_to_binary(N@1);
{address, {address_value, Addr}} ->
Addr;
{bool, {bool_value, B}} ->
case B of
true ->
<<"true"/utf8>>;
false ->
<<"false"/utf8>>
end;
{{fixed_bytes, Size}, {fixed_bytes_value, Data}} ->
<<"0x"/utf8,
(begin
_pipe = string:lowercase(gleam_stdlib:base16_encode(Data)),
gleam@string:slice(_pipe, 0, 2 + (Size * 2))
end)/binary>>;
{bytes, {bytes_value, Data@1}} ->
<<"0x"/utf8,
(string:lowercase(gleam_stdlib:base16_encode(Data@1)))/binary>>;
{string, {string_value, S}} ->
<<<<"\""/utf8, S/binary>>/binary, "\""/utf8>>;
{{array, Element_type}, {array_value, Elements}} ->
Inner = gleam@list:map(
Elements,
fun(El) -> format_single_value(Element_type, El) end
),
<<<<"["/utf8, (gleam@string:join(Inner, <<", "/utf8>>))/binary>>/binary,
"]"/utf8>>;
{{tuple, Element_types}, {tuple_value, Vals}} ->
format_abi_values(Element_types, Vals);
{_, _} ->
<<"<unknown>"/utf8>>
end.
-file("src/gleeth/commands/call.gleam", 156).
-spec format_abi_values(
list(gleeth@ethereum@abi@types:abi_type()),
list(gleeth@ethereum@abi@types:abi_value())
) -> binary().
format_abi_values(Types, Values) ->
Pairs = gleam@list:zip(Types, Values),
Formatted = gleam@list:map(
Pairs,
fun(Pair) ->
{T, V} = Pair,
format_single_value(T, V)
end
),
case Formatted of
[Single] ->
Single;
Multiple ->
<<<<"("/utf8, (gleam@string:join(Multiple, <<", "/utf8>>))/binary>>/binary,
")"/utf8>>
end.
-file("src/gleeth/commands/call.gleam", 119).
-spec decode_with_abi(binary(), binary(), binary()) -> {ok, binary()} |
{error, gleeth@ethereum@abi@types:abi_error()}.
decode_with_abi(Abi_file, Function_name, Response) ->
gleam@result:'try'(
begin
_pipe = simplifile:read(Abi_file),
gleam@result:map_error(
_pipe,
fun(_) ->
{invalid_abi_json,
<<"Cannot read ABI file: "/utf8, Abi_file/binary>>}
end
)
end,
fun(Abi_json_str) ->
gleam@result:'try'(
gleeth@ethereum@abi@json:parse_abi(Abi_json_str),
fun(Entries) ->
gleam@result:'try'(
gleeth@ethereum@abi@json:find_function(
Entries,
Function_name
),
fun(Entry) ->
Output_types = gleeth@ethereum@abi@json:output_types(
Entry
),
case Output_types of
[] ->
{ok, <<"(void)"/utf8>>};
_ ->
gleam@result:'try'(
begin
_pipe@1 = gleeth@utils@hex:decode(
Response
),
gleam@result:map_error(
_pipe@1,
fun(_) ->
{decode_error,
<<"Invalid hex in response"/utf8>>}
end
)
end,
fun(Data) ->
gleam@result:'try'(
gleeth@ethereum@abi@decode:decode(
Output_types,
Data
),
fun(Values) ->
{ok,
format_abi_values(
Output_types,
Values
)}
end
)
end
)
end
end
)
end
)
end
).
-file("src/gleeth/commands/call.gleam", 70).
-spec print_contract_response(
binary(),
binary(),
list(binary()),
binary(),
gleam@option:option(binary())
) -> nil.
print_contract_response(
Contract_address,
Function_name,
Parameters,
Response,
Abi_file
) ->
gleam_stdlib:println(<<"Contract Call Results:"/utf8>>),
gleam_stdlib:println(<<" Contract: "/utf8, Contract_address/binary>>),
gleam_stdlib:println(
<<<<" Function: "/utf8, Function_name/binary>>/binary, "()"/utf8>>
),
case Parameters of
[] ->
nil;
Params ->
gleam_stdlib:println(<<" Parameters:"/utf8>>),
gleam@list:each(
Params,
fun(Param) ->
gleam_stdlib:println(<<" "/utf8, Param/binary>>)
end
)
end,
gleam_stdlib:println(<<" Raw Response: "/utf8, Response/binary>>),
case Abi_file of
{some, File} ->
case decode_with_abi(File, Function_name, Response) of
{ok, Decoded} ->
gleam_stdlib:println(<<" Decoded: "/utf8, Decoded/binary>>);
{error, Err} ->
gleam_stdlib:println(
<<" ABI decode failed: "/utf8,
(abi_error_message(Err))/binary>>
),
case decode_response(Function_name, Response) of
{ok, Decoded@1} ->
gleam_stdlib:println(
<<" Decoded (heuristic): "/utf8,
Decoded@1/binary>>
);
{error, _} ->
nil
end
end;
none ->
case decode_response(Function_name, Response) of
{ok, Decoded@2} ->
gleam_stdlib:println(
<<" Decoded: "/utf8, Decoded@2/binary>>
);
{error, _} ->
nil
end
end.
-file("src/gleeth/commands/call.gleam", 20).
-spec execute(
gleeth@provider:provider(),
binary(),
binary(),
list(binary()),
gleam@option:option(binary())
) -> {ok, nil} | {error, gleeth@rpc@types:gleeth_error()}.
execute(Provider, Contract_address, Function_call, Parameters, Abi_file) ->
gleam@result:'try'(
gleeth@utils@validation:validate_address(Contract_address),
fun(Validated_address) ->
gleam@result:'try'(
parse_parameters(Parameters),
fun(Parsed_params) ->
gleam@result:'try'(
gleeth@ethereum@contract:build_call_data(
Function_call,
Parsed_params
),
fun(Call_data) ->
gleam@result:'try'(
gleeth@rpc@methods:call_contract(
Provider,
Validated_address,
Call_data
),
fun(Response) ->
print_contract_response(
Contract_address,
Function_call,
Parameters,
Response,
Abi_file
),
{ok, nil}
end
)
end
)
end
)
end
).