diff --git a/ebin/gajudesk.app b/ebin/gajudesk.app index be511cf..e8655d9 100644 --- a/ebin/gajudesk.app +++ b/ebin/gajudesk.app @@ -3,7 +3,7 @@ {registered,[]}, {included_applications,[]}, {applications,[stdlib,kernel,sasl,ssl]}, - {vsn,"0.6.2"}, + {vsn,"0.6.3"}, {modules,[gajudesk,gd_con,gd_grids,gd_gui,gd_jt, gd_sophia_editor,gd_sup,gd_v,gd_v_devman,gd_v_netman, gd_v_wallman]}, diff --git a/include/gd.hrl b/include/gd.hrl index 69d9aff..f65ccdb 100644 --- a/include/gd.hrl +++ b/include/gd.hrl @@ -1,23 +1,23 @@ %% Node, Chain and Net represent the physical network. -record(node, - {ip = {161,97,102,143} :: string() | inet:ip_address(), - external = 3013 :: none | inet:port_number(), % 3013 - internal = none :: none | inet:port_number(), % 3113 - rosetta = none :: none | inet:port_number(), % 8080 - channel = none :: none | inet:port_number(), % 3014 - mdw = none :: none | inet:port_number()}). % 4000 + {ip = "groot.testnet.gajumaru.io" :: string() | inet:ip_address(), + external = 3013 :: none | inet:port_number(), % 3013 + internal = none :: none | inet:port_number(), % 3113 + rosetta = none :: none | inet:port_number(), % 8080 + channel = none :: none | inet:port_number(), % 3014 + mdw = none :: none | inet:port_number()}). % 4000 -record(chain, - {id = <<"groot.devnet">> :: binary(), - coins = ["gaju"] :: [string()], - nodes = [#node{}] :: [#node{}]}). + {id = <<"groot.testnet">> :: binary(), + coins = ["gaju"] :: [string()], + nodes = [#node{}] :: [#node{}]}). -record(net, - {id = <<"devnet">> :: binary(), - chains = [#chain{}] :: [#chain{}]}). + {id = <<"testnet">> :: binary(), + chains = [#chain{}] :: [#chain{}]}). @@ -29,17 +29,17 @@ -record(coin, - {id = "gaju" :: string(), - mint = <<"groot.devnet">> :: binary(), - acs = [#ac{}] :: [#ac{}]}). + {id = "gaju" :: string(), + mint = <<"groot.testnet">> :: binary(), + acs = [#ac{}] :: [#ac{}]}). %% Balance, POA, Key, TXs, all culminate in capturing a complete Wallet view. -record(balance, - {coin = "gaju" :: string(), - total = 0 :: non_neg_integer(), - dist = [{<<"groot.devnet">>, 0}] :: [{Chain :: binary(), non_neg_integer()}]}). + {coin = "gaju" :: string(), + total = 0 :: non_neg_integer(), + dist = [{<<"groot.testnet">>, 0}] :: [{Chain :: binary(), non_neg_integer()}]}). -record(poa, @@ -77,14 +77,14 @@ -record(wallet, - {version = 2 :: integer(), - name = "" :: string(), - poas = [] :: [#poa{}], - keys = [] :: [#key{}], - chain_id = <<"groot.devnet">> :: binary(), - endpoint = #node{} :: #node{}, - nets = [#net{}] :: [#net{}], - txs = #{} :: gajudesk:key_txs()}). + {version = 2 :: integer(), + name = "" :: string(), + poas = [] :: [#poa{}], + keys = [] :: [#key{}], + chain_id = <<"groot.testnet">> :: binary(), + endpoint = #node{} :: #node{}, + nets = [#net{}] :: [#net{}], + txs = #{} :: gajudesk:key_txs()}). diff --git a/src/gajudesk.erl b/src/gajudesk.erl index 6f78294..1af75b2 100644 --- a/src/gajudesk.erl +++ b/src/gajudesk.erl @@ -3,7 +3,7 @@ %%% @end -module(gajudesk). --vsn("0.6.2"). +-vsn("0.6.3"). -behavior(application). -author("Craig Everett "). -copyright("QPQ AG "). diff --git a/src/gd_con.erl b/src/gd_con.erl index 90e7a2c..04fe166 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -3,14 +3,14 @@ %%% @end -module(gd_con). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). -behavior(gen_server). -export([show_ui/1, - open_wallet/2, close_wallet/0, new_wallet/3, import_wallet/3, drop_wallet/2, + open_wallet/2, close_wallet/0, new_wallet/4, import_wallet/3, drop_wallet/2, selected/1, network/0, password/2, refresh/0, @@ -80,13 +80,14 @@ close_wallet() -> gen_server:cast(?MODULE, close_wallet). --spec new_wallet(Name, Path, Password) -> ok - when Name :: string(), +-spec new_wallet(Net, Name, Path, Password) -> ok + when Net :: mainnet | testnet | devnet, + Name :: string(), Path :: string(), Password :: string(). -new_wallet(Name, Path, Password) -> - gen_server:cast(?MODULE, {new_wallet, Name, Path, Password}). +new_wallet(Net, Name, Path, Password) -> + gen_server:cast(?MODULE, {new_wallet, Net, Name, Path, Password}). -spec import_wallet(Name, Path, Password) -> ok @@ -332,10 +333,8 @@ init(none) -> read_prefs() -> case file:consult(prefs_path()) of - {ok, Prefs} -> - proplists:to_map(Prefs); - _ -> - #{gd_v_wallman => #{geometry => {582,335,500,300}}} + {ok, Prefs} -> proplists:to_map(Prefs); + _ -> #{} end. @@ -399,8 +398,8 @@ handle_cast(close_wallet, State) -> ok = gd_gui:show([]), NewState = do_show_ui(gd_v_wallman, NextState), {noreply, NewState}; -handle_cast({new_wallet, Name, Path, Password}, State) -> - NewState = do_new_wallet(Name, Path, Password, State), +handle_cast({new_wallet, Net, Name, Path, Password}, State) -> + NewState = do_new_wallet(Net, Name, Path, Password, State), {noreply, NewState}; handle_cast({import_wallet, Name, Path, Password}, State) -> NewState = do_import_wallet(Name, Path, Password, State), @@ -532,6 +531,7 @@ do_show_ui(Name, State = #s{tasks = Tasks, prefs = Prefs}) -> Win = Name:start_link({TaskPrefs, TaskData}), PID = wx_object:get_pid(Win), Mon = monitor(process, PID), + ok = Name:to_front(Win), UI = #ui{name = Name, pid = PID, wx = Win, mon = Mon}, State#s{tasks = [UI | Tasks]} end. @@ -561,12 +561,15 @@ do_add_node(New, State) -> do_set_sole_node(TOTN = #node{external = none}, State) -> do_set_sole_node(TOTN#node{external = 3013}, State); -do_set_sole_node(New = #node{ip = IP, external = Port}, State = #s{wallet = W}) -> +do_set_sole_node(New = #node{ip = IP, external = Port}, State = #s{wallet = W, wallets = Ws, pass = Pass}) -> ok = hz:chain_nodes([{IP, Port}]), case ensure_hz_set(New) of {ok, ChainID} -> + #wallet{name = Name} = W, + RW = lists:keyfind(Name, #wr.name, Ws), Net = #net{id = ChainID, chains = [#chain{id = ChainID, nodes = [New]}]}, NewWallet = W#wallet{chain_id = ChainID, endpoint = New, nets = [Net]}, + ok = save_wallet(RW, Pass, NewWallet), NewState = State#s{wallet = NewWallet}, do_refresh(NewState); Error -> @@ -982,22 +985,26 @@ do_deploy3(#{"tx_hash" := TXHash}) -> end. -do_rename_key(ID, NewName, State = #s{wallet = W}) -> - #wallet{poas = POAs, keys = Keys} = W, +do_rename_key(ID, NewName, State = #s{wallet = W, wallets = Wallets, pass = Pass}) -> + #wallet{name = Name, poas = POAs, keys = Keys} = W, + RW = lists:keyfind(Name, #wr.name, Wallets), A = lists:keyfind(ID, #poa.id, POAs), K = lists:keyfind(ID, #key.id, Keys), NewPOAs = lists:keystore(ID, #poa.id, POAs, A#poa{name = NewName}), NewKeys = lists:keystore(ID, #key.id, Keys, K#key{name = NewName}), NewWallet = W#wallet{poas = NewPOAs, keys = NewKeys}, + ok = save_wallet(RW, Pass, NewWallet), ok = gd_gui:show(NewPOAs), State#s{wallet = NewWallet}. -do_drop_key(ID, State = #s{wallet = W}) -> - #wallet{poas = POAs, keys = Keys} = W, +do_drop_key(ID, State = #s{wallet = W, wallets = Wallets, pass = Pass}) -> + #wallet{name = Name, poas = POAs, keys = Keys} = W, + RW = lists:keyfind(Name, #wr.name, Wallets), NewPOAs = lists:keydelete(ID, #poa.id, POAs), NewKeys = lists:keydelete(ID, #key.id, Keys), NewWallet = W#wallet{poas = NewPOAs, keys = NewKeys}, + ok = save_wallet(RW, Pass, NewWallet), ok = gd_gui:show(NewPOAs), State#s{wallet = NewWallet}. @@ -1022,12 +1029,25 @@ do_open_wallet(Path, Phrase, State) -> default_wallet() -> - DevNet = #net{id = <<"devnet">>, chains = [#chain{}]}, -% TestChain1 = #chain{id = <<"groot.testnet">>, -% nodes = [#node{ip = {1,2,3,4}}, #node{ip = {5,6,7,8}}]}, -% TestChain2 = #chain{id = <<"test_ac.testnet">>, -% nodes = [#node{ip = {11,12,13,14}}, #node{ip = {15,16,17,18}}]}, -% TestNet = #net{id = <<"testnet">>, chains = [TestChain1, TestChain2]}, + default_wallet(testnet). + +default_wallet(mainnet) -> + Node = #node{ip = "groot.mainnet.gajumaru.io"}, + Groot = #chain{id = <<"groot.mainnet">>, + nodes = [Node]}, + MainNet = #net{id = <<"mainnet">>, chains = [Groot]}, + #wallet{nets = [MainNet], endpoint = Node}; +default_wallet(testnet) -> + Node = #node{ip = "groot.testnet.gajumaru.io"}, + Groot = #chain{id = <<"groot.testnet">>, + nodes = [Node]}, + TestNet = #net{id = <<"testnet">>, chains = [Groot]}, + #wallet{nets = [TestNet], endpoint = Node}; +default_wallet(devnet) -> + % TODO: This accounts for the nature of devnets by defining *no* chains. + % The GUI/CON will need to manage this properly when encountered and prompt. + DevNet = #net{id = <<"devnet">>, + chains = []}, #wallet{nets = [DevNet]}. @@ -1071,17 +1091,23 @@ do_stop(State = #s{prefs = Prefs}) -> NewState. -do_new_wallet(Name, Path, Password, State = #s{wallets = Wallets, prefs = Prefs}) -> +do_new_wallet(Net, Name, Path, Password, State = #s{wallets = Wallets, prefs = Prefs}) -> case lists:keyfind(Name, #wr.name, Wallets) of false -> NextState = do_close_wallet(State), Pass = pass(Password), HasPass = Pass =/= none, Entry = #wr{name = Name, path = Path, pass = HasPass}, - New = #wallet{name = Name}, + DW = #wallet{endpoint = Node} = default_wallet(Net), + New = DW#wallet{name = Name}, ok = save_wallet(Entry, Pass, New), ok = gd_gui:show([]), ok = gd_gui:wallet(Name), + ok = + case ensure_hz_set(Node) of + {ok, ChainID} -> gd_gui:chain(ChainID, Node); + Error -> gd_gui:trouble(Error) + end, NewWallets = [Entry | Wallets], NewPrefs = put_prefs(wallets, NewWallets, Prefs), ok = persist(NewPrefs), diff --git a/src/gd_grids.erl b/src/gd_grids.erl index b4ccb38..2dde378 100644 --- a/src/gd_grids.erl +++ b/src/gd_grids.erl @@ -37,7 +37,7 @@ %%% @end -module(gd_grids). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_gui.erl b/src/gd_gui.erl index a38a157..ed64cae 100644 --- a/src/gd_gui.erl +++ b/src/gd_gui.erl @@ -3,7 +3,7 @@ %%% @end -module(gd_gui). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_jt.erl b/src/gd_jt.erl index a9205a2..8c1e9fd 100644 --- a/src/gd_jt.erl +++ b/src/gd_jt.erl @@ -15,7 +15,7 @@ %%% translation library is retained). -module(gd_jt). --vsn("0.6.2"). +-vsn("0.6.3"). -export([read_translations/1, j/2, oneshot_j/2]). diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index ec21967..c4df9c8 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -1,5 +1,5 @@ -module(gd_sophia_editor). --vsn("0.6.2"). +-vsn("0.6.3"). -export([new/1, update/2, get_text/1, set_text/2]). diff --git a/src/gd_sup.erl b/src/gd_sup.erl index 56bfbac..f40ab5f 100644 --- a/src/gd_sup.erl +++ b/src/gd_sup.erl @@ -12,7 +12,7 @@ %%% @end -module(gd_sup). --vsn("0.6.2"). +-vsn("0.6.3"). -behaviour(supervisor). -author("Craig Everett "). -copyright("QPQ AG "). diff --git a/src/gd_v.erl b/src/gd_v.erl index ae507c0..bb64014 100644 --- a/src/gd_v.erl +++ b/src/gd_v.erl @@ -1,5 +1,5 @@ -module(gd_v). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 9547761..e9b3d0c 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -1,5 +1,5 @@ -module(gd_v_devman). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_v_netman.erl b/src/gd_v_netman.erl index e2d43c3..56acd95 100644 --- a/src/gd_v_netman.erl +++ b/src/gd_v_netman.erl @@ -1,5 +1,5 @@ -module(gd_v_netman). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_v_wallman.erl b/src/gd_v_wallman.erl index ca0208a..3681b08 100644 --- a/src/gd_v_wallman.erl +++ b/src/gd_v_wallman.erl @@ -1,5 +1,5 @@ -module(gd_v_wallman). --vsn("0.6.2"). +-vsn("0.6.3"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). @@ -89,12 +89,34 @@ init({Prefs, Manifest}) -> ok = wxFrame:setSizer(Frame, MainSz), ok = wxSizer:layout(MainSz), - ok = gd_v:safe_size(Frame, Prefs), + NewPrefs = + case maps:is_key(geometry, Prefs) of + true -> + Prefs; + false -> + Display = wxDisplay:new(), + {_, _, W, H} = wxDisplay:getGeometry(Display), + ok = wxDisplay:destroy(Display), + WW = 500, + WH = 350, + X = (W div 2) - (WW div 2), + Y = (H div 2) - (WH div 2), + Prefs#{geometry => {X, Y, WW, WH}} + end, + ok = gd_v:safe_size(Frame, NewPrefs), ok = wxFrame:connect(Frame, command_button_clicked), ok = wxFrame:connect(Frame, close_window), true = wxFrame:show(Frame), ok = wxListBox:connect(Picker, command_listbox_doubleclicked), + ok = + case length(Manifest) =:= 0 of + false -> + ok; + true -> + self() ! new, + ok + end, State = #s{wx = Wx, frame = Frame, lang = Lang, j = J, prefs = Prefs, wallets = Manifest, picker = Picker, @@ -121,6 +143,9 @@ handle_cast(Unexpected, State) -> {noreply, State}. +handle_info(new, State) -> + NewState = do_new(State), + {noreply, NewState}; handle_info(Unexpected, State) -> ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), {noreply, State}. @@ -252,6 +277,7 @@ do_new(State = #s{frame = Frame, j = J, prefs = Prefs}) -> {defaultDir, DefaultDir}, {defaultFile, "default.gaju"}, {wildCard, "*.gaju"}, + {sz, {300, 270}}, {style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}], Dialog = wxFileDialog:new(Frame, Options), case wxFileDialog:showModal(Dialog) of @@ -276,6 +302,7 @@ do_new2(Path, J, Frame) -> Dialog = wxDialog:new(Frame, ?wxID_ANY, J("New Wallet"), [{size, {400, 250}}]), Sizer = wxBoxSizer:new(?wxVERTICAL), + Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]), NameSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Name")}]), NameTx = wxTextCtrl:new(Dialog, ?wxID_ANY), _ = wxSizer:add(NameSz, NameTx, zxw:flags(wide)), @@ -294,12 +321,14 @@ do_new2(Path, J, Frame) -> _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), + _ = wxBoxSizer:add(Sizer, Network, zxw:flags(base)), _ = wxSizer:add(Sizer, NameSz, zxw:flags(base)), _ = wxSizer:add(Sizer, PassSz, zxw:flags(base)), _ = wxSizer:add(Sizer, PassConSz, zxw:flags(base)), _ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)), ok = wxDialog:setSizer(Dialog, Sizer), + ok = wxDialog:setSize(Dialog, {300, 270}), ok = wxBoxSizer:layout(Sizer), ok = wxDialog:center(Dialog), ok = wxStyledTextCtrl:setFocus(NameTx), @@ -307,6 +336,12 @@ do_new2(Path, J, Frame) -> Result = case wxDialog:showModal(Dialog) of ?wxID_OK -> + Net = + case wxRadioBox:getSelection(Network) of + 0 -> mainnet; + 1 -> testnet; + _ -> mainnet + end, Name = case wxTextCtrl:getValue(NameTx) of "" -> Path; @@ -318,17 +353,17 @@ do_new2(Path, J, Frame) -> {P, P} -> P; {_, _} -> bad end, - do_new3(Name, Path, Pass); + do_new3(Net, Name, Path, Pass); ?wxID_CANCEL -> abort end, ok = wxDialog:destroy(Dialog), Result. -do_new3(_, _, bad) -> +do_new3(_, _, _, bad) -> abort; -do_new3(Name, Path, Pass) -> - gd_con:new_wallet(Name, Path, Pass). +do_new3(Net, Name, Path, Pass) -> + gd_con:new_wallet(Net, Name, Path, Pass). do_import(State = #s{frame = Frame, j = J, prefs = Prefs}) -> diff --git a/zomp.meta b/zomp.meta index 5ece91c..e9d00d5 100644 --- a/zomp.meta +++ b/zomp.meta @@ -2,9 +2,9 @@ {type,gui}. {modules,[]}. {prefix,"gd"}. -{desc,"A desktop client for the Gajumaru network of blockchain networks"}. {author,"Craig Everett"}. -{package_id,{"otpr","gajudesk",{0,6,2}}}. +{desc,"A desktop client for the Gajumaru network of blockchain networks"}. +{package_id,{"otpr","gajudesk",{0,6,3}}}. {deps,[{"otpr","hakuzaru",{0,6,1}}, {"otpr","eblake2",{1,0,1}}, {"otpr","base58",{0,1,1}},