From 3afc3cfa026cdbd470540c184311474841b2bc8c Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 10 Oct 2024 15:05:28 +0900 Subject: [PATCH] Dekajigger spend encoding from string inputs --- src/gmc_con.erl | 39 +++++++++++++++++++++------- src/gmc_gui.erl | 69 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/gmc_con.erl b/src/gmc_con.erl index b7440d0..7c7cc8a 100644 --- a/src/gmc_con.erl +++ b/src/gmc_con.erl @@ -12,6 +12,7 @@ -behavior(gen_server). -export([open_wallet/2, close_wallet/0, password/2, + nonce/1, spend/2, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1]). -export([encrypt/2, decrypt/2]). -export([start_link/0, stop/0, save/1]). @@ -61,6 +62,23 @@ password(Old, New) -> gen_server:cast(?MODULE, {password, Old, New}). +-spec nonce(ID) -> {ok, Nonce} | {error, Reason} + when ID :: clutch:id(), + Nonce :: integer(), + Reason :: term(). % FIXME +% FIXME + +nonce(_) -> {ok, 42}. + + +-spec spend(KeyID, TX) -> ok + when KeyID :: clutch:id(), + TX :: #spend_tx{}. + +spend(KeyID, TX) -> + gen_server:cast(?MODULE, {spend, KeyID, TX}). + + -spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok when Type :: {eddsa, ed25519}, Size :: 256, @@ -200,6 +218,15 @@ handle_call(Unexpected, From, State) -> %% The gen_server:handle_cast/2 callback. %% See: http://erlang.org/doc/man/gen_server.html#Module:handle_cast-2 +handle_cast({open_wallet, Path, Phrase}, State) -> + NewState = do_open_wallet(Path, Phrase, State), + {noreply, NewState}; +handle_cast({password, Old, New}, State) -> + NewState = do_password(Old, New, State), + {noreply, NewState}; +handle_cast({spend, KeyID, TX}, State) -> + ok = do_spend(KeyID, TX, State), + {noreply, State}; handle_cast({make_key, Name, Seed, Encoding, Transform}, State) -> NewState = do_make_key(Name, Seed, Encoding, Transform, State), {noreply, NewState}; @@ -212,12 +239,6 @@ handle_cast({rename_key, ID, NewName}, State) -> handle_cast({drop_key, ID}, State) -> NewState = do_drop_key(ID, State), {noreply, NewState}; -handle_cast({open_wallet, Path, Phrase}, State) -> - NewState = do_open_wallet(Path, Phrase, State), - {noreply, NewState}; -handle_cast({password, Old, New}, State) -> - NewState = do_password(Old, New, State), - {noreply, NewState}; handle_cast(stop, State) -> ok = zx:stop(), {noreply, State}; @@ -443,7 +464,7 @@ do_spend(KeyID, TX, State = #s{wallet = #wallet{keys = Keys}}) -> do_spend2(PrivKey, #spend_tx{sender_id = SenderID, - recipient_id = RecipientId, + recipient_id = RecipientID, amount = Amount, gas_price = GasPrice, gas = Gas, @@ -455,7 +476,7 @@ do_spend2(PrivKey, Vsn = 1, Fields = [{sender_id, SenderID}, - {recipient_id, RecipientId}, + {recipient_id, RecipientID}, {amount, Amount}, {gas_price, GasPrice}, {gas, Gas}, @@ -470,7 +491,7 @@ do_spend2(PrivKey, {gas, int}, {ttl, int}, {nonce, int}, - {payload, binary}], + {payload, binary}], BinaryTX = aeser_chain_objects:serialize(Type, Vsn, Template, Fields), NetworkTX = <>, Signature = ecu_eddsa:sign_detached(NetworkTX, PrivKey), diff --git a/src/gmc_gui.erl b/src/gmc_gui.erl index 8289ae2..284f7f6 100644 --- a/src/gmc_gui.erl +++ b/src/gmc_gui.erl @@ -589,8 +589,17 @@ spend(State = #s{picker = Picker}) -> Selected -> spend(Selected + 1, State) end. -spend(Selected, State = #s{frame = Frame, j = J, accounts = Accounts}) -> - #poa{id = ID, name = Name} = lists:nth(Selected, Accounts), +spend(Selected, State = #s{accounts = Accounts}) -> + POA = #poa{id = ID} = lists:nth(Selected, Accounts), + case gmc_con:nonce(ID) of + {ok, Nonce} -> + spend2(POA, Nonce, State); + {error, Reason} -> + tell("spend/2 failed to get nonce with ~tp", [Reason]), + State + end. + +spend2(#poa{id = ID, name = Name}, Nonce, State = #s{frame = Frame, j = J}) -> Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Transfer"), [{size, {500, 400}}]), Sizer = wxBoxSizer:new(?wxVERTICAL), @@ -636,12 +645,64 @@ spend(Selected, State = #s{frame = Frame, j = J, accounts = Accounts}) -> ok = wxFrame:center(Dialog), ok = case wxDialog:showModal(Dialog) of - ?wxID_OK -> gmc_con:drop_key(ID); - ?wxID_CANCEL -> ok + ?wxID_OK -> + {ok, PK} = decode_account_id(ID), + TX = + #spend_tx{sender_id = aeser_id:create(account, PK), + recipient_id = wxTextCtrl:getValue(ToTx), + amount = wxTextCtrl:getValue(AmtTx), + gas_price = wxSlider:getValue(GasSl), + gas = 20000, + ttl = 175320, + nonce = Nonce, + payload = wxTextCtrl:getValue(DataTx)}, + clean_spend(ID, TX); + ?wxID_CANCEL -> + ok end, ok = wxDialog:destroy(Dialog), State. +clean_spend(_, #spend_tx{recipient_id = ""}) -> + ok; +clean_spend(ID, TX = #spend_tx{recipient_id = S}) when is_list(S) -> + case decode_account_id(S) of + {ok, PK} -> clean_spend(ID, TX#spend_tx{recipient_id = aeser_id:create(account, PK)}); + Error -> tell("Decode recipient_id failed with: ~tp", [Error]) + end; +clean_spend(ID, TX = #spend_tx{amount = S}) when is_list(S) -> + case string_to_price(S) of + {ok, Amount} -> clean_spend(ID, TX#spend_tx{amount = Amount}); + {error, _} -> ok + end; +clean_spend(ID, TX = #spend_tx{gas_price = S}) when is_list(S) -> + case is_int(S) of + true -> clean_spend(ID, TX#spend_tx{gas_price = list_to_integer(S)}); + false -> ok + end; +clean_spend(ID, TX = #spend_tx{gas = S}) when is_list(S) -> + case is_int(S) of + true -> clean_spend(ID, TX#spend_tx{gas = list_to_integer(S)}); + false -> ok + end; +clean_spend(ID, TX = #spend_tx{payload = S}) when is_list(S) -> + clean_spend(ID, TX#spend_tx{payload = list_to_binary(S)}); +clean_spend(ID, TX) -> + gmc_con:spend(ID, TX). + +decode_account_id(S) when is_list(S) -> + decode_account_id(list_to_binary(S)); +decode_account_id(B) -> + try + {account_pubkey, PK} = aeser_api_encoder:decode(B), + {ok, PK} + catch + E:R -> {E, R} + end. + +is_int(S) -> + lists:all(fun(C) -> $0 =< C andalso C =< $9 end, S). + grids_dialogue(State) -> %grids_dialogue(State = #s{frame = Frame, j = J}) ->