From d2d9ae613e5360f7bc7df98d10261cd4a4e53b1e Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 5 Jan 2026 15:08:05 +0900 Subject: [PATCH 01/37] WIP --- src/gd_v_devman.erl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 9dfd43c..e44b868 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -325,13 +325,20 @@ clicked2(State, Contract, Name) -> handle_troubling(State, "No wallet is selected!") end. -clicked3(State = #s{frame = Frame, j = J}, Contract, Name, Selected, Keys) -> +clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Selected, Keys) -> + {FunName, FunType} = Name, + #c{build = #{aaci := AACI}} = Contract, + {aaci, ConName, FunSpecs, _} = AACI, + FunSpec = maps:get(FunName, FunSpecs), + tell("FunName: ~tp", [FunName]), + tell("FunSpec: ~tp", [FunSpec]), + tell("Contract: ~tp", [Contract]), Label = - case element(2, Name) of - call -> "Contract Call"; - dryr -> "Dry Run" + case FunType of + call -> J("Contract Call"); + dryr -> J("Dry Run") end, - Dialog = wxDialog:new(Frame, ?wxID_ANY, J(Label)), + Dialog = wxDialog:new(Frame, ?wxID_ANY, Label), Sizer = wxBoxSizer:new(?wxVERTICAL), KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), -- 2.30.2 From 66f5795c49c577f73b9c852797cae7127b2235a3 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 5 Jan 2026 21:06:04 +0900 Subject: [PATCH 02/37] WIP --- src/gd_con.erl | 5 ++++- src/gd_v_devman.erl | 11 ++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index 88b9e71..996b3fe 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -1349,11 +1349,14 @@ do_tic(MS, State = #s{timer = {T, _}}) -> T = erlang:send_after(MS, self(), tic), State#s{timer = {T, MS}}. +handle_tic(State = #s{wallet = #wallet{poas = []}, timer = {T, MS}}) -> + ok = cancel_timer(T), + NewT = erlang:send_after(MS, self(), tic), + State#s{timer = {NewT, MS}}; handle_tic(State = #s{wallet = This = #wallet{poas = POAs, endpoint = Node}, timer = {T, MS}, selected = Selected}) when Selected > 0 -> - NewState = case ensure_hz_set(Node) of {ok, ChainID} -> diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index e44b868..731a7a2 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -344,6 +344,7 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), ok = wxChoice:setSelection(KeyPicker, Selected - 1), + ArgSz = call_arg_sizer(Dialog, J, FunSpec), {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(Dialog, J), ButtSz = wxBoxSizer:new(?wxHORIZONTAL), Affirm = wxButton:new(Dialog, ?wxID_OK), @@ -351,6 +352,7 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), _ = wxSizer:add(Sizer, KeySz, zxw:flags(wide)), + _ = wxSizer:add(Sizer, ArgSz, zxw:flags(wide)), _ = wxSizer:add(Sizer, ParamSz, zxw:flags(wide)), _ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)), ok = wxDialog:setSizer(Dialog, Sizer), @@ -384,6 +386,8 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Error -> handle_troubling(State, Error) end. +call_arg_sizer(Dialog, J, FunSpec) -> + call_param_sizer(Dialog, J) -> {ok, Height} = hz:top_height(), DefTTL = Height + 10000, @@ -423,14 +427,15 @@ call_params(Controls) -> call_params([], A) -> {ok, lists:reverse(A)}; call_params([{L, C} | T], A) -> - O = + R = try {ok, list_to_integer(wxTextCtrl:getValue(C))} catch error:badarg -> {error, {L, not_an_integer}} end, - case O of - {ok, N} -> call_params(T, [N | A]); + case R of + {ok, N} when N >= 0 -> call_params(T, [N | A]); + {ok, N} when N < 0 -> {error, {L, neg_integer}}; Error -> Error end. -- 2.30.2 From f9cb72598fc8ebad0d853773e3dca1523c6700bd Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 6 Jan 2026 19:49:10 +0900 Subject: [PATCH 03/37] WIP --- src/gd_v_devman.erl | 105 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 24 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 731a7a2..310458f 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -332,32 +332,32 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, FunSpec = maps:get(FunName, FunSpecs), tell("FunName: ~tp", [FunName]), tell("FunSpec: ~tp", [FunSpec]), - tell("Contract: ~tp", [Contract]), - Label = + CallType = case FunType of call -> J("Contract Call"); dryr -> J("Dry Run") end, + Label = [CallType, ": ", ConName, ".", FunName, "/", integer_to_list(length(element(1, FunSpec)))], Dialog = wxDialog:new(Frame, ?wxID_ANY, Label), Sizer = wxBoxSizer:new(?wxVERTICAL), KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), ok = wxChoice:setSelection(KeyPicker, Selected - 1), - ArgSz = call_arg_sizer(Dialog, J, FunSpec), + {ArgSz, ArgControls, Dimensions} = call_arg_sizer(Dialog, J, FunSpec), {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(Dialog, J), ButtSz = wxBoxSizer:new(?wxHORIZONTAL), Affirm = wxButton:new(Dialog, ?wxID_OK), Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), - _ = wxSizer:add(Sizer, KeySz, zxw:flags(wide)), - _ = wxSizer:add(Sizer, ArgSz, zxw:flags(wide)), - _ = wxSizer:add(Sizer, ParamSz, zxw:flags(wide)), - _ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)), + _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})), + _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), + _ = wxSizer:add(Sizer, KeySz, zxw:flags({base, 5})), + _ = wxSizer:add(Sizer, ArgSz, zxw:flags({wide, 5})), + _ = wxSizer:add(Sizer, ParamSz, zxw:flags({base, 5})), + _ = wxSizer:add(Sizer, ButtSz, zxw:flags({base, 5})), ok = wxDialog:setSizer(Dialog, Sizer), ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, {500, 300}), + ok = wxDialog:setSize(Dialog, Dimensions), ok = wxDialog:center(Dialog), Outcome = case wxDialog:showModal(Dialog) of @@ -365,14 +365,19 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), PK = unicode:characters_to_binary(ID), Controls = - [{"TTL", TTL_Tx}, - {"Gas Price", GasP_Tx}, - {"Gas", Gas_Tx}, - {"Amount", Amount_Tx}], + [{{"TTL", integer}, TTL_Tx}, + {{"Gas Price", integer}, GasP_Tx}, + {{"Gas", integer}, Gas_Tx}, + {{"Amount", integer}, Amount_Tx}], + % TODO: Unify args from the call params and fun args + % Try to give type feedback, probably based on whether Sophia or Erlang terms are chosen case call_params(Controls) of {ok, [TTL, GasP, Gas, Amount]} -> {ok, Nonce} = hz:next_nonce(PK), - {ok, {PK, Nonce, TTL, GasP, Gas, Amount}}; + case extract_args(ArgControls) of + {ok, Args} -> {ok, {PK, Nonce, TTL, GasP, Gas, Amount}, Args}; + E -> E + end; E -> E end; @@ -386,7 +391,59 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Error -> handle_troubling(State, Error) end. -call_arg_sizer(Dialog, J, FunSpec) -> +extract_args({Name, Control}, {OK, Errors}) -> + +extract_args(Controls) -> + extract_args(Controls, []). + +extract_args([H | T], A) -> + case wxTextCtrl:getValue(H) of + "" -> { + +call_arg_sizer(Dialog, J, {CallArgs, ReturnType}) -> + SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Function Spec")}]), + {CallSz, CallControls, Dimensions} = call_sizer(Dialog, J, CallArgs), + ReturnSz = return_sizer(Dialog, J, ReturnType), + _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), + {SpecSz, CallControls, Dimensions}. + +call_sizer(Dialog, J, []) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), + Args = wxStaticText:new(Dialog, ?wxID_ANY, ["[", J("No Args"), "]"]), + _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), + {CallSz, [], {500, 500}}; +call_sizer(Dialog, J, CallArgs) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), + GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), + ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), + ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + AddArg = + fun(Arg = {Name, Type}) -> + L = wxStaticText:new(Dialog, ?wxID_ANY, [Name, " : ", textify(Type)]), + C = wxTextCtrl:new(Dialog, ?wxID_ANY), + _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), + {Arg, C} + end, + _ = wxStaticBoxSizer:add(CallSz, GridSz, zxw:flags(wide)), + Controls = lists:map(AddArg, CallArgs), + {CallSz, Controls, {600, 700}}. + +return_sizer(Dialog, J, ReturnType) -> + ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Return Type")}]), + Return = wxStaticText:new(Dialog, ?wxID_ANY, textify(ReturnType)), + _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), + ReturnSz. + +textify({integer, _, _}) -> "int"; +textify({boolean, _, _}) -> "bool"; +textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); +textify({{bytes, any}, _, _}) -> "bytes()"; +textify({T, _, _}) when is_atom(T) -> atom_to_list(T); +textify({T, _, _}) when is_list(T) -> T; +textify({T, _, _}) -> io_lib:format("~tp", [T]). + call_param_sizer(Dialog, J) -> {ok, Height} = hz:top_height(), @@ -410,14 +467,14 @@ call_param_sizer(Dialog, J) -> Amount_L = wxStaticText:new(Dialog, ?wxID_ANY, J("TX Amount")), Amount_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags(base)), - _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags(wide)), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags(base)), - _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags(wide)), - _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags(base)), - _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags(wide)), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags(base)), - _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags(wide)), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. -- 2.30.2 From df441184639ab4c6ac68b330dfebbf6c99f88936 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 8 Jan 2026 15:59:46 +0900 Subject: [PATCH 04/37] WIP --- src/gd_v_devman.erl | 225 ++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 310458f..98abb7a 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -8,7 +8,7 @@ %-behavior(gd_v). -include_lib("wx/include/wx.hrl"). -export([to_front/1]). --export([set_manifest/1, open_contract/1, call_result/2, dryrun_result/2, trouble/1]). +-export([set_manifest/1, open_contract/1, write_console/2, call_result/2, dryrun_result/2, trouble/1]). -export([start_link/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). @@ -87,6 +87,14 @@ open_contract(Address) -> wx_object:cast(?MODULE, {open_contract, Address}). +-spec write_console(ConID, Message) -> ok + when ConID :: gajudesk:id(), + Message :: unicode:chardata(). + +write_console(ConID, Message) -> + wx_object:cast(?MODULE, {write_console, ConID, Message}). + + -spec call_result(ConID, CallInfo) -> ok when ConID :: gajudesk:id(), CallInfo :: map(). @@ -220,6 +228,9 @@ handle_cast(to_front, State = #s{frame = Frame}) -> handle_cast({open_contract, Address}, State) -> NewState = load2(State, Address), {noreply, NewState}; +handle_cast({write_console, ConID, Message}, State) -> + ok = do_write_console(State, ConID, Message), + {noreply, State}; handle_cast({call_result, ConID, CallInfo}, State) -> ok = do_call_result(State, ConID, CallInfo), {noreply, State}; @@ -327,7 +338,7 @@ clicked2(State, Contract, Name) -> clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Selected, Keys) -> {FunName, FunType} = Name, - #c{build = #{aaci := AACI}} = Contract, + #c{id = ConID, build = #{aaci := AACI}} = Contract, {aaci, ConName, FunSpecs, _} = AACI, FunSpec = maps:get(FunName, FunSpecs), tell("FunName: ~tp", [FunName]), @@ -365,19 +376,17 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), PK = unicode:characters_to_binary(ID), Controls = - [{{"TTL", integer}, TTL_Tx}, - {{"Gas Price", integer}, GasP_Tx}, - {{"Gas", integer}, Gas_Tx}, - {{"Amount", integer}, Amount_Tx}], - % TODO: Unify args from the call params and fun args - % Try to give type feedback, probably based on whether Sophia or Erlang terms are chosen + [{{"TTL", fun gt_0/1}, TTL_Tx}, + {{"Gas Price", fun gt_0/1}, GasP_Tx}, + {{"Gas", fun gt_0/1}, Gas_Tx}, + {{"Amount", fun gte_0/1}, Amount_Tx}], case call_params(Controls) of {ok, [TTL, GasP, Gas, Amount]} -> + {Message, CArgs} = extract_args(ArgControls), + ok = gd_v_devman:write_console(ConID, Message), {ok, Nonce} = hz:next_nonce(PK), - case extract_args(ArgControls) of - {ok, Args} -> {ok, {PK, Nonce, TTL, GasP, Gas, Amount}, Args}; - E -> E - end; + CallParams = {PK, Nonce, TTL, GasP, Gas, Amount}, + {ok, CallParams, CArgs}; E -> E end; @@ -386,19 +395,29 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, end, ok = wxDialog:destroy(Dialog), case Outcome of - {ok, Params} -> clicked4(State, Contract, Name, Params); - cancel -> State; - Error -> handle_troubling(State, Error) + {ok, Params, Args} -> clicked4(State, Contract, Name, Params, Args); + cancel -> State; + Error -> handle_troubling(State, Error) end. -extract_args({Name, Control}, {OK, Errors}) -> - extract_args(Controls) -> extract_args(Controls, []). -extract_args([H | T], A) -> - case wxTextCtrl:getValue(H) of - "" -> { +extract_args([], Acc) -> + pack_args(Acc); +extract_args([{Name, Control} | T], Acc) -> + String = wxTextCtrl:getValue(Control), + extract_args(T, [{Name, String} | Acc]). + +pack_args(Args) -> + pack_args(Args, [], []). + +pack_args([], M, A) -> + Message = unicode:characters_to_list(["Call Args:\n", M]), + {Message, A}; +pack_args([{N, S} | T], M, A) -> + pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). + call_arg_sizer(Dialog, J, {CallArgs, ReturnType}) -> SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Function Spec")}]), @@ -414,19 +433,24 @@ call_sizer(Dialog, J, []) -> _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), {CallSz, [], {500, 500}}; call_sizer(Dialog, J, CallArgs) -> + ScrollWin = wxScrolledWindow:new(Dialog), + ScrollSz = wxBoxSizer:new(?wxVERTICAL), + ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), + ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), AddArg = - fun(Arg = {Name, Type}) -> - L = wxStaticText:new(Dialog, ?wxID_ANY, [Name, " : ", textify(Type)]), - C = wxTextCtrl:new(Dialog, ?wxID_ANY), + fun({Name, Type}) -> + L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), + C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), - {Arg, C} + {Name, C} end, - _ = wxStaticBoxSizer:add(CallSz, GridSz, zxw:flags(wide)), + _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), + _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), Controls = lists:map(AddArg, CallArgs), {CallSz, Controls, {600, 700}}. @@ -479,29 +503,52 @@ call_param_sizer(Dialog, J) -> {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. call_params(Controls) -> - call_params(Controls, []). + call_params(Controls, {[], []}). -call_params([], A) -> - {ok, lists:reverse(A)}; -call_params([{L, C} | T], A) -> +call_params([], {Acc, []}) -> + {ok, lists:reverse(Acc)}; +call_params([], {_, Errors}) -> + {error, lists:reverse(Errors)}; +call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> + String = wxTextCtrl:getValue(Control), + case Validate(String) of + {ok, Value} -> call_params(T, {[Value | Acc], Errors}); + {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) + end. + +gt_0(S) -> + C = "Must be an integer greater than 0", R = try - {ok, list_to_integer(wxTextCtrl:getValue(C))} + {ok, list_to_integer(S)} catch - error:badarg -> {error, {L, not_an_integer}} + error:badarg -> {error, {S, C}} end, case R of - {ok, N} when N >= 0 -> call_params(T, [N | A]); - {ok, N} when N < 0 -> {error, {L, neg_integer}}; - Error -> Error + {ok, N} when N > 0 -> {ok, N}; + {ok, N} when N =< 0 -> {error, {S, C}}; + Error -> Error + end. + +gte_0(S) -> + C = "Must be a non-negative integer.", + R = + try + {ok, list_to_integer(S)} + catch + error:badarg -> {error, {S, C}} + end, + case R of + {ok, N} when N >= 0 -> {ok, N}; + {ok, N} when N < 0 -> {error, {S, C}}; + Error -> Error end. clicked4(State, - #c{id = ConID, build = #{aaci := AACI}, funs = {_, Funs}}, + #c{id = ConID, build = #{aaci := AACI}}, {Name, Type}, - {PK, Nonce, TTL, GasP, Gas, Amt}) -> - #f{args = ArgFields} = maps:get(Name, Funs), - Args = lists:map(fun get_arg/1, ArgFields), + {PK, Nonce, TTL, GasP, Gas, Amt}, + Args) -> case hz:contract_call(PK, Nonce, Gas, GasP, Amt, TTL, AACI, ConID, Name, Args) of {ok, UnsignedTX} -> case Type of @@ -522,28 +569,27 @@ do_dry_run(State, ConID, TX) -> State. -do_call_result(#s{tabs = TopBook, cons = {Consbook, Contracts}}, ConID, CallInfo) -> +do_write_console(#s{tabs = TopBook, cons = {Consbook, Contracts}}, ConID, Message) -> case lookup_contract(ConID, Contracts) of {#c{cons = Console}, ZeroIndex} -> _ = wxNotebook:changeSelection(TopBook, 1), _ = wxNotebook:changeSelection(Consbook, ZeroIndex), - Out = io_lib:format("Call Result:~n~p~n~n", [CallInfo]), + Out = [Message, "\n\n"], wxTextCtrl:appendText(Console, Out); error -> - tell(info, "Received result for ~p:~n~p ", [ConID, CallInfo]) + tell(info, "Received result for ~p:~n~p ", [ConID, Message]) end. -do_dryrun_result(#s{tabs = TopBook, cons = {Consbook, Contracts}}, ConID, CallInfo) -> - case lookup_contract(ConID, Contracts) of - {#c{cons = Console}, ZeroIndex} -> - _ = wxNotebook:changeSelection(TopBook, 1), - _ = wxNotebook:changeSelection(Consbook, ZeroIndex), - Out = io_lib:format("Call Result:~n~p~n~n", [CallInfo]), - wxTextCtrl:appendText(Console, Out); - error -> - tell(info, "Received result for ~p:~n~p ", [ConID, CallInfo]) - end. +do_call_result(State, ConID, CallInfo) -> + Message = io_lib:format("Call Result:~n~p", [CallInfo]), + do_write_console(State, ConID, Message). + + +do_dryrun_result(State, ConID, CallInfo) -> + Message = io_lib:format("Call Result:~n~p", [CallInfo]), + do_write_console(State, ConID, Message). + lookup_contract(ConID, Contracts) -> lookup_contract(ConID, Contracts, 0). @@ -687,55 +733,44 @@ deploy3(State, InitSpec, Build) -> end. deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, Selected, Keys) -> - InitArgs = element(1, InitSpec), Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Deploy Contract")), Sizer = wxBoxSizer:new(?wxVERTICAL), - ScrollWin = wxScrolledWindow:new(Dialog), - ScrollSz = wxBoxSizer:new(?wxVERTICAL), - ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), - ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), - FunName = unicode:characters_to_list(["init/", integer_to_list(length(InitArgs))]), - FunSz = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, FunName}]), - KeySz = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, J("Signature Key")}]), - KeyPicker = wxChoice:new(ScrollWin, ?wxID_ANY, [{choices, Keys}]), + KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), + KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), ok = wxChoice:setSelection(KeyPicker, Selected - 1), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(ScrollWin, J), + {ArgSz, ArgControls, Dimensions} = call_arg_sizer(Dialog, J, InitSpec), + {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(Dialog, J), ButtSz = wxBoxSizer:new(?wxHORIZONTAL), Affirm = wxButton:new(Dialog, ?wxID_OK), Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), - GridSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - ArgFields = make_arg_fields(ScrollWin, GridSz, InitArgs), - _ = wxStaticBoxSizer:add(FunSz, GridSz, zxw:flags(wide)), - _ = wxStaticBoxSizer:add(ScrollSz, FunSz, [{proportion, 1}, {flag, ?wxEXPAND}]), - _ = wxStaticBoxSizer:add(ScrollSz, KeySz, [{proportion, 0}, {flag, ?wxEXPAND}]), - _ = wxStaticBoxSizer:add(ScrollSz, ParamSz, [{proportion, 0}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(Sizer, ScrollWin, [{proportion, 5}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(Sizer, ButtSz, [{proportion, 1}, {flag, ?wxEXPAND}]), + _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})), + _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), + _ = wxSizer:add(Sizer, KeySz, zxw:flags({base, 5})), + _ = wxSizer:add(Sizer, ArgSz, zxw:flags({wide, 5})), + _ = wxSizer:add(Sizer, ParamSz, zxw:flags({base, 5})), + _ = wxSizer:add(Sizer, ButtSz, zxw:flags({base, 5})), ok = wxDialog:setSizer(Dialog, Sizer), ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, {500, 500}), + ok = wxDialog:setSize(Dialog, Dimensions), ok = wxDialog:center(Dialog), Outcome = case wxDialog:showModal(Dialog) of ?wxID_OK -> ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), PK = unicode:characters_to_binary(ID), - IArgs = lists:map(fun get_arg/1, ArgFields), Controls = - [{"TTL", TTL_Tx}, - {"Gas Price", GasP_Tx}, - {"Gas", Gas_Tx}, - {"Amount", Amount_Tx}], + [{{"TTL", fun gt_0/1}, TTL_Tx}, + {{"Gas Price", fun gt_0/1}, GasP_Tx}, + {{"Gas", fun gt_0/1}, Gas_Tx}, + {{"Amount", fun gte_0/1}, Amount_Tx}], case call_params(Controls) of {ok, [TTL, GasP, Gas, Amount]} -> + {Message, CArgs} = extract_args(ArgControls), + ok = tell(Message), {ok, Nonce} = hz:next_nonce(PK), DeployParams = {PK, Nonce, TTL, GasP, Gas, Amount}, - {ok, DeployParams, IArgs}; + {ok, DeployParams, CArgs}; E -> E end; @@ -755,19 +790,6 @@ deploy5(State, Build, Params, Args) -> State. -make_arg_fields(ScrollWin, GridSz, Args) -> - MakeArgField = - fun({AN, T}) -> - tell(info, "~p: Arg: ~p, Type: ~p", [?LINE, AN, T]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - TCT = wxTextCtrl:new(ScrollWin, ?wxID_ANY), - _ = wxFlexGridSizer:add(GridSz, ANT, [{proportion, 0}, {flag, ?wxEXPAND}]), - _ = wxFlexGridSizer:add(GridSz, TCT, [{proportion, 0}, {flag, ?wxEXPAND}]), - {T, TCT} - end, - lists:map(MakeArgField, Args). - - open(State = #s{frame = Frame, j = J}) -> Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Open Contract Source")), Sizer = wxBoxSizer:new(?wxVERTICAL), @@ -1160,23 +1182,6 @@ load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j State#s{cons = {Consbook, NewPages}, buttons = NewButtons}. -get_arg({list, AFs, _}) -> - lists:map(fun get_arg/1, AFs); -get_arg({record, AFs}) -> - get_record(AFs); -get_arg({tuple, AFs}) -> - list_to_tuple(lists:map(fun get_arg/1, AFs)); -get_arg({map, [Key, Value]}) -> - #{get_arg(Key) => get_arg(Value)}; -get_arg({variant, AFs, [VariantOne | _]}) -> - Elems = lists:map(fun get_arg/1, AFs), - list_to_tuple([VariantOne | Elems]); -get_arg({_, TextCtrl}) -> - wxTextCtrl:getValue(TextCtrl). - -get_record([{L, A} | T]) -> - [{L, get_arg(A)} | get_record(T)]. - fun_interfaces(ScrollWin, FunSz, Buttons, Funs, J) -> MakeIface = fun(Name, {Args, _}) -> -- 2.30.2 From 34a73a8e99bad590d1ca31d57757ac99314ce585 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 28 Jan 2026 19:58:55 +0900 Subject: [PATCH 05/37] Fix silly state bug --- src/gd_con.erl | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index 996b3fe..e00c5e7 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -632,23 +632,26 @@ do_refresh(State = #s{wallet = #wallet{endpoint = Node}}) -> do_refresh2(ChainID, State = #s{wallet = W = #wallet{poas = POAs}}) -> - CheckBalance = check_balance(ChainID), + CheckBalance = check_balance(ChainID, "gaju"), NewPOAs = lists:map(CheckBalance, POAs), ok = gd_gui:show(NewPOAs), NewW = W#wallet{chain_id = ChainID, poas = NewPOAs}, State#s{wallet = NewW}. -check_balance(ChainID) -> - fun(This = #poa{id = ID, balances = [#balance{coin = "gaju", total = OldBalance}]}) -> +check_balance(ChainID, Coin) -> + fun(This = #poa{id = ID, balances = Balances}) -> + #balance{dist = Dist} = lists:keyfind(Coin, #balance.coin, Balances), + Old = proplists:get_value(ChainID, Dist, 0), Pucks = case hz:acc(ID) of - {ok, #{"balance" := P}} -> P; - {error, "Account not found"} -> 0; - {error, timeout} -> OldBalance + {ok, #{"balance" := Old}} -> Old; + {ok, #{"balance" := New}} -> New; + {error, "Account not found"} -> 0; + {error, timeout} -> Old end, - Dist = [{ChainID, Pucks}], - Gaju = #balance{coin = "gaju", total = Pucks, dist = Dist}, + NewDist = [{ChainID, Pucks}], + Gaju = #balance{coin = "gaju", total = Pucks, dist = NewDist}, This#poa{balances = [Gaju]} end. @@ -1291,13 +1294,17 @@ do_close_wallet(State = #s{wallet = Current, wallets = Wallets, pass = Pass}) -> State#s{selected = 0, pass = none, wallet = none}. -save_wallet(#wr{path = Path, pass = false}, none, Wallet) -> +save_wallet(#wr{path = Path, pass = false}, none, Wallet = #wallet{name = Name}) -> ok = filelib:ensure_dir(Path), - file:write_file(Path, term_to_binary(Wallet)); -save_wallet(#wr{path = Path, pass = true}, Pass, Wallet) -> + ok = log(info, "Saving plain wallet ~ts file to disk...", [Name]), + ok = file:write_file(Path, term_to_binary(Wallet)), + log(info, "Wallet ~ts file written.", [Name]); +save_wallet(#wr{path = Path, pass = true}, Pass, Wallet = #wallet{name = Name}) -> ok = filelib:ensure_dir(Path), Cipher = encrypt(Pass, term_to_binary(Wallet)), - file:write_file(Path, Cipher). + ok = log(info, "Saving cipher wallet ~ts file to disk.", [Name]), + ok = file:write_file(Path, Cipher), + log(info, "Wallet ~ts file written.", [Name]). read(Path, none) -> @@ -1357,15 +1364,17 @@ handle_tic(State = #s{wallet = This = #wallet{poas = POAs, endpoint = Node}, timer = {T, MS}, selected = Selected}) when Selected > 0 -> + % TODO: The closure below is kind of silly. The internal hz:acc/1 account will + % Expand to become hz:acc/2, accepting a chain ID later. NewState = case ensure_hz_set(Node) of {ok, ChainID} -> POA = #poa{id = ID} = lists:nth(Selected, POAs), - CheckBalance = check_balance(ChainID), + CheckBalance = check_balance(ChainID, "gaju"), NewPOA = CheckBalance(POA), NewPOAs = lists:keystore(ID, #poa.id, POAs, NewPOA), ok = gd_gui:show(NewPOAs), - State#s{wallet = This#wallet{poas = POAs}}; + State#s{wallet = This#wallet{poas = NewPOAs}}; Error -> ok = log(info, "Balance update on tic failed with: ~p", [Error]), State @@ -1390,6 +1399,7 @@ cancel_timer(T) -> persist(Prefs) -> Path = prefs_path(), ok = filelib:ensure_dir(Path), + ok = log(info, "Writing prefs to disk."), zx_lib:write_terms(Path, proplists:from_map(Prefs)). -- 2.30.2 From 3a570f000e2a48b7cdb3359f86efe4dc8d960729 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 12 Feb 2026 17:46:52 +0900 Subject: [PATCH 06/37] Adapting in the new hz functions --- src/gd_v_devman.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 98abb7a..1d1b440 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -1227,7 +1227,8 @@ close_instance(State = #s{cons = {Consbook, Pages}, buttons = Buttons}) -> State; Index -> {#c{funs = {_, IFaces}}, NewPages} = take_nth(Index + 1, Pages), - IDs = list_iface_buttons(IFaces), + log(info, "IFaces: ~tp", [IFaces]), + IDs = list_iface_buttons(maps:values(IFaces)), NewButtons = maps:without(IDs, Buttons), true = wxNotebook:deletePage(Consbook, Index), State#s{cons = {Consbook, NewPages}, buttons = NewButtons} @@ -1248,7 +1249,7 @@ compile(Source) -> case so_compiler:from_string(Source, Options) of {ok, Build} -> ACI = maps:get(aci, Build), - AACI = hz:prepare_aaci(ACI), + AACI = hz_aaci:prepare(ACI), Complete = maps:put(aaci, AACI, Build), {ok, Complete}; Other -> -- 2.30.2 From fcf44f55a13f3e81b0aefb4660af793124eeb0e9 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Fri, 13 Feb 2026 15:07:22 +0900 Subject: [PATCH 07/37] De-snaggle some of the snaggle-toothed save routine nonsense --- src/gd_v_devman.erl | 158 +++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 99 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 1d1b440..caac3ba 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -945,15 +945,14 @@ open_hash3(State, Address, Source) -> end. -% TODO: Break this down -- tons of things in here recur. -save(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) -> +save(State = #s{prefs = Prefs, code = {Codebook, Pages}}) -> case wxNotebook:getSelection(Codebook) of ?wxNOT_FOUND -> State; Index -> case lists:nth(Index + 1, Pages) of #p{path = {file, Path}, code = Widget} -> - Source = wxTextCtrl:getValue(Widget), + Source = wxStyledTextCtrl:getText(Widget), case filelib:ensure_dir(Path) of ok -> case file:write_file(Path, Source) of @@ -968,7 +967,7 @@ save(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) State end; Page = #p{path = {hash, Hash}, code = Widget} -> - DefaultDir = + DefDir = case maps:find(dir, Prefs) of {ok, PrefDir} -> PrefDir; @@ -978,117 +977,78 @@ save(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) D -> filename:basename(D) end end, - Options = - [{message, J("Save Location")}, - {defaultDir, DefaultDir}, - {defaultFile, unicode:characters_to_list([Hash, ".aes"])}, - {wildCard, "*.aes"}, - {style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}], - Dialog = wxFileDialog:new(Frame, Options), - NewState = - case wxFileDialog:showModal(Dialog) of - ?wxID_OK -> - Dir = wxFileDialog:getDirectory(Dialog), - case wxFileDialog:getFilename(Dialog) of - "" -> - State; - Name -> - File = - case filename:extension(Name) of - ".aes" -> Name; - _ -> Name ++ ".aes" - end, - Path = filename:join(Dir, File), - Source = gd_sophia_editor:get_text(Widget), - case filelib:ensure_dir(Path) of - ok -> - case file:write_file(Path, Source) of - ok -> - true = wxNotebook:setPageText(Codebook, Index, File), - NewPrefs = maps:put(dir, Dir, Prefs), - NewPage = Page#p{path = {file, Path}}, - NewPages = store_nth(Index + 1, NewPage, Pages), - NewCode = {Codebook, NewPages}, - State#s{prefs = NewPrefs, code = NewCode}; - Error -> - ok = handle_troubling(State, Error), - State - end; - Error -> - ok = handle_troubling(State, Error), - State - end - end; - ?wxID_CANCEL -> - State - end, - ok = wxFileDialog:destroy(Dialog), - NewState + DefName = unicode:characters_to_list([Hash, ".aes"]), + save_dialog(State, DefDir, DefName, Widget, Index, Page) end end. -% TODO: Break this down -- tons of things in here recur. -rename(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) -> +rename(State = #s{code = {Codebook, Pages}}) -> case wxNotebook:getSelection(Codebook) of ?wxNOT_FOUND -> State; Index -> case lists:nth(Index + 1, Pages) of Page = #p{path = {file, Path}, code = Widget} -> - DefaultDir = filename:dirname(Path), - Options = - [{message, J("Save Location")}, - {defaultDir, DefaultDir}, - {defaultFile, filename:basename(Path)}, - {wildCard, "*.aes"}, - {style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}], - Dialog = wxFileDialog:new(Frame, Options), - NewState = - case wxFileDialog:showModal(Dialog) of - ?wxID_OK -> - Dir = wxFileDialog:getDirectory(Dialog), - case wxFileDialog:getFilename(Dialog) of - "" -> - State; - Name -> - File = - case filename:extension(Name) of - ".aes" -> Name; - _ -> Name ++ ".aes" - end, - NewPath = filename:join(Dir, File), - Source = gd_sophia_editor:get_text(Widget), - case filelib:ensure_dir(NewPath) of - ok -> - case file:write_file(NewPath, Source) of - ok -> - true = wxNotebook:setPageText(Codebook, Index, File), - NewPrefs = maps:put(dir, Dir, Prefs), - NewPage = Page#p{path = {file, NewPath}}, - NewPages = store_nth(Index + 1, NewPage, Pages), - NewCode = {Codebook, NewPages}, - State#s{prefs = NewPrefs, code = NewCode}; - Error -> - ok = handle_troubling(State, Error), - State - end; - Error -> - ok = handle_troubling(State, Error), - State - end - end; - ?wxID_CANCEL -> - State - end, - ok = wxFileDialog:destroy(Dialog), - NewState; + DefDir = filename:dirname(Path), + DefName = filename:basename(Path), + save_dialog(State, DefDir, DefName, Widget, Index, Page); #p{path = {hash, _}} -> save(State) end end. +save_dialog(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}, + DefDir, DefName, Widget, Index, Page) -> + Options = + [{message, J("Save Location")}, + {defaultDir, DefDir}, + {defaultFile, DefName}, + {wildCard, "*.aes"}, + {style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}], + Dialog = wxFileDialog:new(Frame, Options), + NewState = + case wxFileDialog:showModal(Dialog) of + ?wxID_OK -> + Dir = wxFileDialog:getDirectory(Dialog), + case wxFileDialog:getFilename(Dialog) of + "" -> + State; + Name -> + File = + case filename:extension(Name) of + ".aes" -> Name; + _ -> Name ++ ".aes" + end, + NewPath = filename:join(Dir, File), + Source = gd_sophia_editor:get_text(Widget), + case filelib:ensure_dir(NewPath) of + ok -> + case file:write_file(NewPath, Source) of + ok -> + true = wxNotebook:setPageText(Codebook, Index, File), + NewPrefs = maps:put(dir, Dir, Prefs), + NewPage = Page#p{path = {file, NewPath}}, + NewPages = store_nth(Index + 1, NewPage, Pages), + NewCode = {Codebook, NewPages}, + State#s{prefs = NewPrefs, code = NewCode}; + Error -> + ok = handle_troubling(State, Error), + State + end; + Error -> + ok = handle_troubling(State, Error), + State + end + end; + ?wxID_CANCEL -> + State + end, + ok = wxFileDialog:destroy(Dialog), + NewState. + + close_source(State = #s{code = {Codebook, Pages}}) -> case wxNotebook:getSelection(Codebook) of ?wxNOT_FOUND -> -- 2.30.2 From ae17d21f4fa2eeea32975f3e0e588c604e9affc4 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 25 Feb 2026 16:21:56 +0900 Subject: [PATCH 08/37] doodles --- src/gd_v_call.erl | 226 ++++++++++++++++++++++++++++++++++++++++++++ src/gd_v_devman.erl | 154 ++---------------------------- 2 files changed, 233 insertions(+), 147 deletions(-) create mode 100644 src/gd_v_call.erl diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl new file mode 100644 index 0000000..a051678 --- /dev/null +++ b/src/gd_v_call.erl @@ -0,0 +1,226 @@ +-module(gd_v_devman). +-vsn("0.8.1"). +-author("Craig Everett "). +-copyright("QPQ AG "). +-license("GPL-3.0-or-later"). + +-behavior(wx_object). +%-behavior(gd_v). +-include_lib("wx/include/wx.hrl"). +-export([to_front/1]). +% -export([]). +-export([start_link/1]). +-export([init/1, terminate/2, code_change/3, + handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). +-include("$zx_include/zx_logger.hrl"). +-include("gd.hrl"). + + +% Widgets +-record(w, + {name = none :: atom() | {FunName :: binary(), call | dryr}, + id = 0 :: integer(), + wx = none :: none | wx:wx_object()}). + +% State +-record(s, + {wx = none :: none | wx:wx_object(), + frame = none :: none | wx:wx_object(), + lang = en :: en | jp, + j = none :: none | fun(), + args = [] :: [#wx{}], + ttl = #wx{} :: #wx{}, + gasprice = #wx{} :: #wx{}, + gas = #wx{} :: #wx{}, + amount = #wx{} :: #wx{}, + retry = #wx{} :: #wx{}, + copy = #wx{} :: #wx{}, + done = #wx{} :: #wx{}}). + + + +%%% Startup Functions + +start_link(Args) -> + wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). + + +init({Prefs, {FunName, FunType}, ConID, AACI}) -> + {aaci, ConName, FunSpecs, _} = AACI, + FunSpec = maps:get(FunName, FunSpecs), + CallType = + case FunType of + call -> J("Contract Call"); + dryr -> J("Dry Run") + end, + Title = [CallType, ": ", ConName, ".", FunName, "/", integer_to_list(length(element(1, FunSpec)))], + Lang = maps:get(lang, Prefs, en_us), + Trans = gd_jt:read_translations(?MODULE), + J = gd_jt:j(Lang, Trans), + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, Title), + + {ArgSz, Args} = call_arg_sizer(Frame, J, FunSpec), + {ParamSz, TTL_T, GasPriceT, GasT, AmountT} = call_param_sizer(Frame, J), + + _ = wxFrame:setSizer(Frame, MainSz), + _ = wxSizer:layout(MainSz), + ok = gd_v:safe_size(Frame, Prefs), + ok = wxFrame:connect(Frame, close_window), + ok = wxFrame:connect(Frame, command_button_clicked), +% TODO: Decide where to put the frame -- should probably be slightly randomized. +% ok = wxFrame:center(Frame), + true = wxFrame:show(Frame), + State = + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + args = Args, + ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, + retry = RetryBn, copy = CopyBn, done = DoneBn}, + {Frame, State}. + + +call_arg_sizer(Frame, J, {CallArgs, ReturnType}) -> + SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), + {CallSz, CallControls, Dimensions} = call_sizer(Frame, J, CallArgs), + ReturnSz = return_sizer(Frame, J, ReturnType), + _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), + {SpecSz, CallControls, Dimensions}. + +call_sizer(Frame, J, []) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), + Args = wxStaticText:new(Frame, ?wxID_ANY, ["[", J("No Args"), "]"]), + _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), + {CallSz, [], {500, 500}}; +call_sizer(Frame, J, CallArgs) -> + ScrollWin = wxScrolledWindow:new(Frame), + ScrollSz = wxBoxSizer:new(?wxVERTICAL), + ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), + ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), + GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), + ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), + ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + AddArg = + fun({Name, Type}) -> + L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), + C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), + _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), + {Name, C} + end, + _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), + _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), + Controls = lists:map(AddArg, CallArgs), + {CallSz, Controls, {600, 700}}. + +return_sizer(Frame, J, ReturnType) -> + ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Return Type")}]), + Return = wxStaticText:new(Frame, ?wxID_ANY, textify(ReturnType)), + _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), + ReturnSz. + + +call_param_sizer(Frame, J) -> + {ok, Height} = hz:top_height(), + DefTTL = Height + 10000, + DefGasP = hz:min_gas_price(), + DefGas = 5000000, + DefAmount = 0, + ParamSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("TX Parameters")}]), + GridSz = wxFlexGridSizer:new(2, 4, 4), + ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), + ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), + TTL_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(TTL_Tx, integer_to_list(DefTTL)), + GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), + GasP_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(GasP_Tx, integer_to_list(DefGasP)), + Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), + Gas_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Gas_Tx, integer_to_list(DefGas)), + Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), + Amount_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), + _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), + {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. + + + +textify({integer, _, _}) -> "int"; +textify({boolean, _, _}) -> "bool"; +textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); +textify({{bytes, any}, _, _}) -> "bytes()"; +textify({T, _, _}) when is_atom(T) -> atom_to_list(T); +textify({T, _, _}) when is_list(T) -> T; +textify({T, _, _}) -> io_lib:format("~tp", [T]). + + +extract_args(Controls) -> + extract_args(Controls, []). + +extract_args([], Acc) -> + pack_args(Acc); +extract_args([{Name, Control} | T], Acc) -> + String = wxTextCtrl:getValue(Control), + extract_args(T, [{Name, String} | Acc]). + +pack_args(Args) -> + pack_args(Args, [], []). + +pack_args([], M, A) -> + Message = unicode:characters_to_list(["Call Args:\n", M]), + {Message, A}; +pack_args([{N, S} | T], M, A) -> + pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). + +call_params(Controls) -> + call_params(Controls, {[], []}). + +call_params([], {Acc, []}) -> + {ok, lists:reverse(Acc)}; +call_params([], {_, Errors}) -> + {error, lists:reverse(Errors)}; +call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> + String = wxTextCtrl:getValue(Control), + case Validate(String) of + {ok, Value} -> call_params(T, {[Value | Acc], Errors}); + {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) + end. + +gt_0(S) -> + C = "Must be an integer greater than 0", + R = + try + {ok, list_to_integer(S)} + catch + error:badarg -> {error, {S, C}} + end, + case R of + {ok, N} when N > 0 -> {ok, N}; + {ok, N} when N =< 0 -> {error, {S, C}}; + Error -> Error + end. + +gte_0(S) -> + C = "Must be a non-negative integer.", + R = + try + {ok, list_to_integer(S)} + catch + error:badarg -> {error, {S, C}} + end, + case R of + {ok, N} when N >= 0 -> {ok, N}; + {ok, N} when N < 0 -> {error, {S, C}}; + Error -> Error + end. diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index caac3ba..9d08e37 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -322,7 +322,9 @@ clicked(State = #s{cons = {Consbook, Contracts}}, Name) -> ok = tell(warning, "Inconcievable! No notebook page is selected!"), State; Index -> - Contract = lists:nth(Index + 1, Contracts), + #c{id = ConID, build = #{aaci := AACI}} = lists:nth(Index + 1, Contracts), + + clicked2(State, Contract, Name) end. @@ -337,8 +339,10 @@ clicked2(State, Contract, Name) -> end. clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Selected, Keys) -> - {FunName, FunType} = Name, #c{id = ConID, build = #{aaci := AACI}} = Contract, + {FunDef, ConID, AACI} + + {aaci, ConName, FunSpecs, _} = AACI, FunSpec = maps:get(FunName, FunSpecs), tell("FunName: ~tp", [FunName]), @@ -400,149 +404,6 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Error -> handle_troubling(State, Error) end. -extract_args(Controls) -> - extract_args(Controls, []). - -extract_args([], Acc) -> - pack_args(Acc); -extract_args([{Name, Control} | T], Acc) -> - String = wxTextCtrl:getValue(Control), - extract_args(T, [{Name, String} | Acc]). - -pack_args(Args) -> - pack_args(Args, [], []). - -pack_args([], M, A) -> - Message = unicode:characters_to_list(["Call Args:\n", M]), - {Message, A}; -pack_args([{N, S} | T], M, A) -> - pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). - - -call_arg_sizer(Dialog, J, {CallArgs, ReturnType}) -> - SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Function Spec")}]), - {CallSz, CallControls, Dimensions} = call_sizer(Dialog, J, CallArgs), - ReturnSz = return_sizer(Dialog, J, ReturnType), - _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), - {SpecSz, CallControls, Dimensions}. - -call_sizer(Dialog, J, []) -> - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), - Args = wxStaticText:new(Dialog, ?wxID_ANY, ["[", J("No Args"), "]"]), - _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), - {CallSz, [], {500, 500}}; -call_sizer(Dialog, J, CallArgs) -> - ScrollWin = wxScrolledWindow:new(Dialog), - ScrollSz = wxBoxSizer:new(?wxVERTICAL), - ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), - ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), - GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - AddArg = - fun({Name, Type}) -> - L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), - C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), - _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), - {Name, C} - end, - _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), - _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), - Controls = lists:map(AddArg, CallArgs), - {CallSz, Controls, {600, 700}}. - -return_sizer(Dialog, J, ReturnType) -> - ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Return Type")}]), - Return = wxStaticText:new(Dialog, ?wxID_ANY, textify(ReturnType)), - _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), - ReturnSz. - -textify({integer, _, _}) -> "int"; -textify({boolean, _, _}) -> "bool"; -textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); -textify({{bytes, any}, _, _}) -> "bytes()"; -textify({T, _, _}) when is_atom(T) -> atom_to_list(T); -textify({T, _, _}) when is_list(T) -> T; -textify({T, _, _}) -> io_lib:format("~tp", [T]). - - -call_param_sizer(Dialog, J) -> - {ok, Height} = hz:top_height(), - DefTTL = Height + 10000, - DefGasP = hz:min_gas_price(), - DefGas = 5000000, - DefAmount = 0, - ParamSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("TX Parameters")}]), - GridSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - TTL_L = wxStaticText:new(Dialog, ?wxID_ANY, "TTL"), - TTL_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(TTL_Tx, integer_to_list(DefTTL)), - GasP_L = wxStaticText:new(Dialog, ?wxID_ANY, J("Gas Price")), - GasP_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(GasP_Tx, integer_to_list(DefGasP)), - Gas_L = wxStaticText:new(Dialog, ?wxID_ANY, J("Gas")), - Gas_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(Gas_Tx, integer_to_list(DefGas)), - Amount_L = wxStaticText:new(Dialog, ?wxID_ANY, J("TX Amount")), - Amount_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), - _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. - -call_params(Controls) -> - call_params(Controls, {[], []}). - -call_params([], {Acc, []}) -> - {ok, lists:reverse(Acc)}; -call_params([], {_, Errors}) -> - {error, lists:reverse(Errors)}; -call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> - String = wxTextCtrl:getValue(Control), - case Validate(String) of - {ok, Value} -> call_params(T, {[Value | Acc], Errors}); - {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) - end. - -gt_0(S) -> - C = "Must be an integer greater than 0", - R = - try - {ok, list_to_integer(S)} - catch - error:badarg -> {error, {S, C}} - end, - case R of - {ok, N} when N > 0 -> {ok, N}; - {ok, N} when N =< 0 -> {error, {S, C}}; - Error -> Error - end. - -gte_0(S) -> - C = "Must be a non-negative integer.", - R = - try - {ok, list_to_integer(S)} - catch - error:badarg -> {error, {S, C}} - end, - case R of - {ok, N} when N >= 0 -> {ok, N}; - {ok, N} when N < 0 -> {error, {S, C}}; - Error -> Error - end. clicked4(State, #c{id = ConID, build = #{aaci := AACI}}, @@ -785,7 +646,6 @@ deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, Selected, Keys) -> end. deploy5(State, Build, Params, Args) -> - tell(info, "Build: ~p", [Build]), ok = gd_con:deploy(Build, Params, Args), State. @@ -952,7 +812,7 @@ save(State = #s{prefs = Prefs, code = {Codebook, Pages}}) -> Index -> case lists:nth(Index + 1, Pages) of #p{path = {file, Path}, code = Widget} -> - Source = wxStyledTextCtrl:getText(Widget), + Source = gd_sophia_editor:get_text(Widget), case filelib:ensure_dir(Path) of ok -> case file:write_file(Path, Source) of -- 2.30.2 From 713650f88b8de7a59c827cb0d01c2488190d7759 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Fri, 27 Feb 2026 01:34:30 +0900 Subject: [PATCH 09/37] doodles --- src/gd_con.erl | 2 +- src/gd_v_call.erl | 29 ++++++++++++++--------------- src/gd_v_devman.erl | 17 ++++------------- src/gd_v_netman.erl | 2 +- src/gd_v_wallman.erl | 2 +- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index e00c5e7..710d25c 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -16,7 +16,7 @@ refresh/0, nonce/1, spend/1, chain/1, grids/1, sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, dry_run/2, - deploy/3, + deploy/3, make_call/3, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index a051678..a9f2060 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -8,7 +8,6 @@ %-behavior(gd_v). -include_lib("wx/include/wx.hrl"). -export([to_front/1]). -% -export([]). -export([start_link/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). @@ -45,7 +44,7 @@ start_link(Args) -> wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). -init({Prefs, {FunName, FunType}, ConID, AACI}) -> +init({{FunName, FunType}, ConID, AACI}) -> {aaci, ConName, FunSpecs, _} = AACI, FunSpec = maps:get(FunName, FunSpecs), CallType = @@ -53,8 +52,9 @@ init({Prefs, {FunName, FunType}, ConID, AACI}) -> call -> J("Contract Call"); dryr -> J("Dry Run") end, - Title = [CallType, ": ", ConName, ".", FunName, "/", integer_to_list(length(element(1, FunSpec)))], - Lang = maps:get(lang, Prefs, en_us), + Arity = integer_to_list(length(element(1, FunSpec))), + Title = [CallType, ": ", ConName, ".", FunName, "/", Arity], + Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), Wx = wx:new(), @@ -62,7 +62,7 @@ init({Prefs, {FunName, FunType}, ConID, AACI}) -> {ArgSz, Args} = call_arg_sizer(Frame, J, FunSpec), {ParamSz, TTL_T, GasPriceT, GasT, AmountT} = call_param_sizer(Frame, J), - + _ = wxFrame:setSizer(Frame, MainSz), _ = wxSizer:layout(MainSz), ok = gd_v:safe_size(Frame, Prefs), @@ -101,6 +101,8 @@ call_sizer(Frame, J, CallArgs) -> GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), + _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), AddArg = fun({Name, Type}) -> L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), @@ -109,8 +111,6 @@ call_sizer(Frame, J, CallArgs) -> _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), {Name, C} end, - _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), - _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), Controls = lists:map(AddArg, CallArgs), {CallSz, Controls, {600, 700}}. @@ -143,19 +143,18 @@ call_param_sizer(Frame, J) -> Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), Amount_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. - textify({integer, _, _}) -> "int"; textify({boolean, _, _}) -> "bool"; textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 9d08e37..eaa98be 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -127,7 +127,7 @@ start_link(Args) -> init({Prefs, Manifest}) -> - Lang = maps:get(lang, Prefs, en_us), + Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), Wx = wx:new(), @@ -338,21 +338,12 @@ clicked2(State, Contract, Name) -> handle_troubling(State, "No wallet is selected!") end. -clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Selected, Keys) -> +clicked3(State = #s{frame = Frame, j = J}, Contract, FunDef, Selected, Keys) -> #c{id = ConID, build = #{aaci := AACI}} = Contract, - {FunDef, ConID, AACI} + ok = gd_con:make_call(FunDef, ConID, AACI), + State. - {aaci, ConName, FunSpecs, _} = AACI, - FunSpec = maps:get(FunName, FunSpecs), - tell("FunName: ~tp", [FunName]), - tell("FunSpec: ~tp", [FunSpec]), - CallType = - case FunType of - call -> J("Contract Call"); - dryr -> J("Dry Run") - end, - Label = [CallType, ": ", ConName, ".", FunName, "/", integer_to_list(length(element(1, FunSpec)))], Dialog = wxDialog:new(Frame, ?wxID_ANY, Label), Sizer = wxBoxSizer:new(?wxVERTICAL), KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), diff --git a/src/gd_v_netman.erl b/src/gd_v_netman.erl index 2c62efe..deeec13 100644 --- a/src/gd_v_netman.erl +++ b/src/gd_v_netman.erl @@ -60,7 +60,7 @@ start_link(Args) -> init({Prefs, Manifest}) -> - Lang = maps:get(lang, Prefs, en_us), + Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), Wx = wx:new(), diff --git a/src/gd_v_wallman.erl b/src/gd_v_wallman.erl index 408f67e..40c2d5e 100644 --- a/src/gd_v_wallman.erl +++ b/src/gd_v_wallman.erl @@ -90,7 +90,7 @@ start_link(Args) -> init({Prefs, Manifest}) -> - Lang = maps:get(lang, Prefs, en_us), + Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), Wx = wx:new(), -- 2.30.2 From 9fa365e83f1d9fa5e757194cbc4bf968f1d44ce3 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 6 Apr 2026 10:59:45 +0900 Subject: [PATCH 10/37] WIP --- include/gdl.hrl | 5 + src/gd_con.erl | 343 +++++++++++++++++++------------------------ src/gd_gui.erl | 7 +- src/gd_lib.erl | 64 +++++++- src/gd_v_call.erl | 235 ++++++++++++++++++++++++----- src/gd_v_devman.erl | 197 ++----------------------- src/gd_v_netman.erl | 6 +- src/gd_v_wallman.erl | 6 +- 8 files changed, 439 insertions(+), 424 deletions(-) create mode 100644 include/gdl.hrl diff --git a/include/gdl.hrl b/include/gdl.hrl new file mode 100644 index 0000000..0b2f1cc --- /dev/null +++ b/include/gdl.hrl @@ -0,0 +1,5 @@ +% Widgets +-record(w, + {name = none :: atom() | {FunName :: binary(), call | dryr}, + id = 0 :: integer(), + wx = none :: none | wx:wx_object()}). diff --git a/src/gd_con.erl b/src/gd_con.erl index 710d25c..b26f0bb 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -14,9 +14,9 @@ selected/1, network/0, password/2, refresh/0, - nonce/1, spend/1, chain/1, grids/1, - sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, dry_run/2, - deploy/3, make_call/3, + nonce/1, spend/1, chain_id/0, grids/1, + sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, + prompt_call/3, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). @@ -154,11 +154,11 @@ spend(TX) -> gen_server:cast(?MODULE, {spend, TX}). --spec chain(ID) -> ok - when ID :: string(). +-spec chain_id() -> {ok, ID} + when ID :: binary(). -chain(ID) -> - gen_server:cast(?MODULE, {chain, ID}). +chain_id() -> + gen_server:cast(?MODULE, {chain_id, ID}). -spec grids(string()) -> ok. @@ -188,21 +188,15 @@ sign_tx(Request) -> gen_server:cast(?MODULE, {sign_tx, Request}). --spec sign_call(ConID, PubKey, TX) -> ok - when ConID :: gajudesk:id(), - PubKey :: gajudesk:id(), - TX :: binary(). +-spec sign_call(ChainID, PubKey, TX) -> Result + when ChainID :: binary(), + PubKey :: gajudesk:id(), + TX :: binary(), + Result :: {ok, SignedTX :: binary()}, + | {error, Reason :: term()}. -sign_call(ConID, PubKey, TX) -> - gen_server:cast(?MODULE, {sign_call, ConID, PubKey, TX}). - - --spec dry_run(ConID, TX) -> ok - when ConID :: gajudesk:id(), - TX :: binary(). - -dry_run(ConID, TX) -> - gen_server:cast(?MODULE, {dry_run, ConID, TX}). +sign_call(ChainID, PubKey, TX) -> + gen_server:call(?MODULE, {sign_call, ChainID, PubKey, TX}). -spec deploy(Build, Params, InitArgs) -> Result @@ -222,6 +216,17 @@ deploy(Build, Params, InitArgs) -> gen_server:cast(?MODULE, {deploy, Build, Params, InitArgs}). +-spec prompt_call(FunDef, ConID, Build) -> ok + when FunDef :: {FunName, FunType}, + FunName :: string(), + FunType :: call | dryr | init, + ConID :: none | binary(), + Build :: map(). % Fixme + +prompt_call(FunDef, ConID, Build) -> + gen_server:cast(?MODULE, {prompt_call, FunDef, ConID, Build}). + + -spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok when Type :: {eddsa, ed25519}, Size :: 256, @@ -401,6 +406,12 @@ handle_call(list_keys, _, State) -> handle_call({nonce, ID}, _, State) -> Response = do_nonce(ID), {reply, Response, State}; +handle_call({chain_id, State) -> + Response = do_chain_id(State), + {reply, Response, NewState}; +handle_call({sign_call, ChainID, PubKey, TX}, _, State) -> + Response = do_sign_call(State, ChainID, PubKey, TX), + {reply, Response, State}; handle_call({open_wallet, Path, Phrase}, _, State) -> {Response, NewState} = do_open_wallet(Path, Phrase, State), {reply, Response, NewState}; @@ -456,9 +467,6 @@ handle_cast(refresh, State) -> handle_cast({spend, TX}, State) -> ok = do_spend(TX, State), {noreply, State}; -handle_cast({chain, ID}, State) -> - NewState = do_chain(ID, State), - {noreply, NewState}; handle_cast({grids, String}, State) -> ok = do_grids(String), {noreply, State}; @@ -471,15 +479,12 @@ handle_cast({sign_binary, Request}, State) -> handle_cast({sign_tx, Request}, State) -> ok = do_sign_tx(Request, State), {noreply, State}; -handle_cast({sign_call, ConID, PubKey, TX}, State) -> - ok = do_sign_call(State, ConID, PubKey, TX), - {noreply, State}; -handle_cast({dry_run, ConID, TX}, State) -> - ok = do_dry_run(ConID, TX), - {noreply, State}; handle_cast({deploy, Build, Params, InitArgs}, State) -> ok = do_deploy(Build, Params, InitArgs, State), {noreply, State}; +handle_cast({prompt_call, FunDef, ConID, Build}) -> + NewState = do_prompt_call(FunDef, ConID, Build, State), + {noreply, NewState}; handle_cast({make_key, Name, Seed, Encoding, Transform}, State) -> NewState = do_make_key(Name, Seed, Encoding, Transform, State), {noreply, NewState}; @@ -588,9 +593,11 @@ task_data(gd_v_devman, #s{}) -> %%% Network operations -do_chain(_, State) -> - tell("Would be doing chain in do_chain/2 here"), - State. +% NOTE: This is temporary. As GD becomes more chain aware this will move. +do_chain_id(#s{wallet = #wallet{chain_id = ChainID}) -> + {ok, ChainID}; +do_chain_id(_) -> + {error, no_chain}. do_add_node(New, State) -> @@ -802,41 +809,13 @@ post_grids_response(ResponseKeys, Request = #{"url" := URL}) -> end. -do_sign_call(#s{wallet = #wallet{keys = Keys, chain_id = ChainID}}, - ConID, - PubKey, - TX) -> - #key{pair = #{secret := SecKey}} = lists:keyfind(PubKey, #key.id, Keys), - SignedTX = hz:sign_tx(TX, SecKey, ChainID), - case hz:post_tx(SignedTX) of - {ok, Data = #{"tx_hash" := TXHash}} -> - ok = tell("TX succeded with: ~p", [TXHash]), - do_sign_call2(ConID, Data); - {ok, WTF} -> - gd_v_devman:trouble({error, WTF}); - Error -> - gd_v_devman:trouble(Error) - end; -do_sign_call(_, _, _, _) -> - gd_v_devman:trouble({error, no_chain}). - -do_sign_call2(ConID, #{"tx_hash" := TXHash}) -> - case hz:tx_info(TXHash) of - {ok, CallInfo = #{"call_info" := #{"return_type" := "ok"}}} -> - gd_v_devman:call_result(ConID, CallInfo); - {error, "Tx not mined"} -> - gd_v_devman:trouble({tx_hash, TXHash}); - {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> - gd_v_devman:trouble({error, Reason}); - Error -> - gd_v_devman:trouble(Error) - end. - - -do_dry_run(ConID, TX) -> - case hz:dry_run(TX) of - {ok, Result} -> gd_v_devman:dryrun_result(ConID, Result); - Other -> gd_v_devmam:trouble({error, ConID, Other}) +do_sign_call(#s{wallet = #wallet{keys = Keys}}, ChainID, PubKey, TX) -> + case lists:keyfind(PubKey, #key.id, Keys) of + #key{pair = #{secret := SecKey}} -> + SignedTX = hz:sign_tx(TX, SecKey, ChainID), + {ok, SignedTX}; + false -> + {error, bad_key} end. @@ -883,23 +862,26 @@ do_network(#s{wallet = #wallet{chain_id = ChainID}}) -> {ok, ChainID}. - -%%% Stateless Operations - -encrypt(Pass, Binary) -> - Flags = [{encrypt, true}, {padding, pkcs_padding}], - crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags). - - -decrypt(Pass, Binary) -> - Flags = [{encrypt, false}, {padding, pkcs_padding}], - crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags). - - -pass(none) -> - none; -pass(Phrase) -> - crypto:hash(sha3_256, Phrase). +do_prompt_call(FunDef, ConID, Build, State = #s{tasks = Tasks, prefs = Prefs}) -> + Name = {ConID, FunDef}, + case do_list_keys(State) of + {ok, Selected, KeyIDs} -> + case lists:keyfind(Name, #ui.name, Tasks) of + #ui{wx = Win} -> + ok = gd_v_call:to_front(Win), + State; + false -> + CallPrefs = maps:get(gd_v_call, Prefs, #{}), + Win = gd_v_call:start_link({CallPrefs, FunDef, ConID, Build, Selected, Keys}), + PID = wx_object:get_pid(Win), + Mon = monitor(process, PID), + UI = #ui{name = Name, pid = PID, wx = Win, mon = Mon}, + State#s{tasks = [UI | Tasks]} + end; + error -> + ok = gd_gui:trouble("ERROR: No Wallet Selected"), + State + end. do_make_key(Name, <<>>, _, Transform, State) -> @@ -950,33 +932,6 @@ do_make_key2(Name, Bin, Transform, State#s{wallet = Updated}. -base64_decode(String) -> - try - {ok, base64:decode(String)} - catch - E:R -> {E, R} - end. - - -transform({sha3, 256}) -> - fun(D) -> crypto:hash(sha3_256, D) end; -transform({sha2, 256}) -> - fun(D) -> crypto:hash(sha256, D) end; -transform({x_or, 256}) -> - fun t_xor/1. - - -t_xor(Bin) -> t_xor(Bin, <<0:256>>). - -t_xor(<>, A) -> - t_xor(T, crypto:exor(H, A)); -t_xor(<<>>, A) -> - A; -t_xor(B, A) -> - H = <<0:(256 - bit_size(B)), B/binary>>, - crypto:exor(H, A). - - do_recover_key(Mnemonic, State) -> case hz_key_master:decode(Mnemonic) of {ok, Seed} -> @@ -1005,54 +960,6 @@ do_recover_key2(Seed, State = #s{wallet = Current, wallets = Wallets, pass = Pas end. -do_mnemonic(ID, #s{wallet = #wallet{keys = Keys}}) -> - case lists:keyfind(ID, #key.id, Keys) of - #key{pair = #{secret := <>}} -> - Mnemonic = hz_key_master:encode(K), - {ok, Mnemonic}; - false -> - {error, bad_key} - end. - - -do_deploy(Build, - {PubKey, Nonce, TTL, GasPrice, Gas, Amount}, - InitArgs, - #s{wallet = #wallet{keys = Keys, chain_id = ChainID}}) -> - #key{pair = #{secret := SecKey}} = lists:keyfind(PubKey, #key.id, Keys), - case hz:contract_create_built(PubKey, - Nonce, Amount, TTL, Gas, GasPrice, - Build, InitArgs) of - {ok, CreateTX} -> do_deploy2(SecKey, CreateTX, ChainID); - Error -> gd_v_devman:trouble(Error) - end. - -do_deploy2(SecKey, CreateTX, ChainID) -> - SignedTX = hz:sign_tx(CreateTX, SecKey, ChainID), - tell(info, "SignedTX: ~p", [SignedTX]), - case hz:post_tx(SignedTX) of - {ok, Data = #{"tx_hash" := TXHash}} -> - ok = tell("Contract deploy TX succeded with: ~p", [TXHash]), - do_deploy3(Data); - {ok, WTF} -> - gd_v_devman:trouble({error, WTF}); - Error -> - gd_v_devman:trouble(Error) - end. - -do_deploy3(#{"tx_hash" := TXHash}) -> - case hz:tx_info(TXHash) of - {ok, #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> - gd_v_devman:open_contract(ConID); - {error, "Tx not mined"} -> - gd_v_devman:trouble({tx_hash, TXHash}); - {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> - gd_v_devman:trouble({error, Reason}); - Error -> - gd_v_devman:trouble(Error) - end. - - 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), @@ -1105,26 +1012,6 @@ do_open_wallet(Path, Phrase, State = #s{timer = Timer}) -> end. -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]}. - - do_password(none, none, State) -> State; do_password(none, New, State = #s{pass = none, @@ -1269,16 +1156,6 @@ maybe_clean(false, _) -> ok. -get_prefs(K, M, D) -> - P = maps:get(?MODULE, M, #{}), - maps:get(K, P, D). - -put_prefs(K, V, M) -> - P = maps:get(?MODULE, M, #{}), - NewP = maps:put(K, V, P), - maps:put(?MODULE, NewP, M). - - do_save(Module, Prefs, State = #s{prefs = Cached}) -> Updated = maps:put(Module, Prefs, Cached), ok = persist(Updated), @@ -1396,6 +1273,92 @@ cancel_timer(T) -> end. + +%%% Stateless Operations + +encrypt(Pass, Binary) -> + Flags = [{encrypt, true}, {padding, pkcs_padding}], + crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags). + + +decrypt(Pass, Binary) -> + Flags = [{encrypt, false}, {padding, pkcs_padding}], + crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags). + + +pass(none) -> + none; +pass(Phrase) -> + crypto:hash(sha3_256, Phrase). + + +base64_decode(String) -> + try + {ok, base64:decode(String)} + catch + E:R -> {E, R} + end. + + +transform({sha3, 256}) -> + fun(D) -> crypto:hash(sha3_256, D) end; +transform({sha2, 256}) -> + fun(D) -> crypto:hash(sha256, D) end; +transform({x_or, 256}) -> + fun t_xor/1. + + +t_xor(Bin) -> t_xor(Bin, <<0:256>>). + +t_xor(<>, A) -> + t_xor(T, crypto:exor(H, A)); +t_xor(<<>>, A) -> + A; +t_xor(B, A) -> + H = <<0:(256 - bit_size(B)), B/binary>>, + crypto:exor(H, A). + + +do_mnemonic(ID, #s{wallet = #wallet{keys = Keys}}) -> + case lists:keyfind(ID, #key.id, Keys) of + #key{pair = #{secret := <>}} -> + Mnemonic = hz_key_master:encode(K), + {ok, Mnemonic}; + false -> + {error, bad_key} + end. + + +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]}. + + +get_prefs(K, M, D) -> + P = maps:get(?MODULE, M, #{}), + maps:get(K, P, D). + +put_prefs(K, V, M) -> + P = maps:get(?MODULE, M, #{}), + NewP = maps:put(K, V, P), + maps:put(?MODULE, NewP, M). + + persist(Prefs) -> Path = prefs_path(), ok = filelib:ensure_dir(Path), diff --git a/src/gd_gui.erl b/src/gd_gui.erl index df258ea..d8e92a8 100644 --- a/src/gd_gui.erl +++ b/src/gd_gui.erl @@ -17,13 +17,9 @@ handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). +-include("gdl.hrl"). --record(w, - {name = none :: atom(), - id = 0 :: integer(), - wx = none :: none | wx:wx_object()}). - -record(h, {win = none :: none | wx:wx_object(), sz = none :: none | wx:wx_object()}). @@ -337,6 +333,7 @@ handle_event(Event, State) -> handle_troubling(#s{frame = Frame}, Info) -> + ok = wxFrame:raise(Frame), zxw:show_message(Frame, Info). diff --git a/src/gd_lib.erl b/src/gd_lib.erl index 9aabc06..d288ca9 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -5,7 +5,15 @@ -module(gd_lib). -vsn("0.8.1"). --export([is_int/1]). +-export([is_int/1, + mono_text/2, mono_text/3, + button/2, button/3]). + +-include("$zx_include/zx_logger.hrl"). +-include("gd.hrl"). +-include("gdl.hrl"). + + -spec is_int(string()) -> boolean(). %% @doc @@ -14,3 +22,57 @@ is_int(S) -> lists:all(fun(C) -> $0 =< C andalso C =< $9 end, S). + + +-spec mono_text(Parent, Name) -> StaticText + when Parent :: wxWindow:wxWindow(), + Name :: term(), + StaticText :: #wx{}. +%% @doc +%% Creates a blank monospace font static text field. +%% @equiv mono_text(Parent, Name, ""). + +mono_text(Parent, Name) -> + mono_text(Parent, Name, ""). + + +-spec mono_text(Parent, Name, Value) -> StaticText + when Parent :: wxWindow:wxWindow(), + Name :: term(), + Value :: string(), + StaticText :: #w{}. +@doc +%% Creats a monospace font static text field with the given value. +%% This exists so that I don't have to remember the difference between how to create a styled +%% wxStaticText vs wxTextCtrl (which has to do it in a weird way because it has a much richer +%% notion of text styling). + +mono_text(Parent, Name, Value) -> + Text = wxStaticText:new(Parent, ?wxID_ANY, Value), + Font = wxFont:new(10, ?wxFONTFAMILY_TELETYPE, ?wxFONT_STYLE_NORMAL, ?wxFONT_WEIGHT_NORMAL), + ok = + case wxStaticText:setFont(Text, Font) of + true -> ok; + false -> log(info, "wxStaticText ~p is already monospace.", [Text) + end, + #w{name = Name, id = wxStaticText:getId(Text), wx = Text}. + + +-spec button(Parent, Label) -> Button + when Parent :: wxWindow:wxWindow(), + Label :: string(), + Button :: #w{}. + +button(Parent, Label) -> + button(Parent, Label, Label). + + +-spec button(Parent, Name, Label) -> Button + when Parent :: wxWindow:wxWindow(), + Name :: term(), + Label :: string(), + Button :: #wx{}. + +button(Parent, Name, Label) -> + Button = wxButton:new(Parent, ?wxID_ANY, [{label, Label}]), + #w{name = Name, id = wxButton:getId(Button), wx = Button}. diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index a9f2060..f316bc4 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -1,4 +1,4 @@ --module(gd_v_devman). +-module(gd_v_call). -vsn("0.8.1"). -author("Craig Everett "). -copyright("QPQ AG "). @@ -7,34 +7,56 @@ -behavior(wx_object). %-behavior(gd_v). -include_lib("wx/include/wx.hrl"). --export([to_front/1]). +-export([to_front/1, result/2]). -export([start_link/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). +-include("gdl.hrl"). -% Widgets --record(w, - {name = none :: atom() | {FunName :: binary(), call | dryr}, - id = 0 :: integer(), - wx = none :: none | wx:wx_object()}). - % State -record(s, - {wx = none :: none | wx:wx_object(), - frame = none :: none | wx:wx_object(), - lang = en :: en | jp, - j = none :: none | fun(), - args = [] :: [#wx{}], - ttl = #wx{} :: #wx{}, - gasprice = #wx{} :: #wx{}, - gas = #wx{} :: #wx{}, - amount = #wx{} :: #wx{}, - retry = #wx{} :: #wx{}, - copy = #wx{} :: #wx{}, - done = #wx{} :: #wx{}}). + {wx = none :: none | wx:wx_object(), + frame = none :: none | wx:wx_object(), + lang = en :: en | jp, + j = none :: none | fun(), + prefs = #{} :: map(), + con_id = <<"">> :: binary(), + fundef = none :: none | fun_def(), + build = none :: none | map(), + args = [] :: [#w{}], + ttl = #w{} :: #w{}, + gasprice = #w{} :: #w{}, + gas = #w{} :: #w{}, + amount = #w{} :: #w{}, + action = #w{} :: #w{}, + tx_hash = #w{} :: #w{}, + out = #w{} :: #w{}, + copy = #w{} :: #w{}}). + + +-type fun_name() :: string(). +-type fun_type() :: call | dryr | init. +-type fun_def() :: {fun_name(), fun_type()}. + + +%%% Interface + +-spec to_front(Win) -> ok + when Win :: wx:wx_object(). + +to_front(Win) -> + wx_object:cast(Win, to_front). + + +-spec result(Win, Outcome) -> ok + when Win :: wx:wx_object(), + Outcome :: term(). + +result(Win, Outcome) -> + wx_object:cast(Win, {result, Outcome}). @@ -44,38 +66,61 @@ start_link(Args) -> wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). -init({{FunName, FunType}, ConID, AACI}) -> - {aaci, ConName, FunSpecs, _} = AACI, - FunSpec = maps:get(FunName, FunSpecs), - CallType = - case FunType of - call -> J("Contract Call"); - dryr -> J("Dry Run") - end, - Arity = integer_to_list(length(element(1, FunSpec))), - Title = [CallType, ": ", ConName, ".", FunName, "/", Arity], +init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), + {aaci, ConName, FunSpecs, _} = maps:get(aaci, Build), + FunSpec = maps:get(FunName, FunSpecs), + {CallType, ActionLabel} = + case FunType of + call -> {J("Contract Call"), J("Submit Call")}; + dryr -> {J("Dry Run"), J("Submit Dry Run")}; + init -> {J("Deploy"), J("Deploy")} + end, + Arity = integer_to_list(length(element(1, FunSpec))), + Title = [CallType, ": ", ConName, ".", FunName, "/", Arity], Wx = wx:new(), Frame = wxFrame:new(Wx, ?wxID_ANY, Title), + MainSz = wxBoxSizer:new(?wxVERTICAL), + + KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Signature Key")}]), + KeyPicker = wxChoice:new(Frame, ?wxID_ANY, [{choices, Keys}]), + _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), {ArgSz, Args} = call_arg_sizer(Frame, J, FunSpec), {ParamSz, TTL_T, GasPriceT, GasT, AmountT} = call_param_sizer(Frame, J), + Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), + + TX_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Transaction Info")}]), + TX_Hash = #w{wx = HashTxt} = gd_lib:mono_text(TX_Sz, tx_hash), + Line = wxStaticLine:new(TX_Sz, [{style, ?wxLI_HORIZONTAL}]), + Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz, out), + Copy = #w{wx = CopyBn} = gd_lib:button(Frame, J("Copy")), + + _ = wxStaticBoxSizer:add(TX_Sz, HashTxt, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({wide, 5})), + + _ = wxSizer:add(MainSz, ArgSz, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, KeySz, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, ParamSz, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, ActionBn, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({wide, 5})), + _ = wxFrame:setSizer(Frame, MainSz), _ = wxSizer:layout(MainSz), ok = gd_v:safe_size(Frame, Prefs), ok = wxFrame:connect(Frame, close_window), ok = wxFrame:connect(Frame, command_button_clicked), -% TODO: Decide where to put the frame -- should probably be slightly randomized. -% ok = wxFrame:center(Frame), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - args = Args, - ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, - retry = RetryBn, copy = CopyBn, done = DoneBn}, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + con_id = ConID, build = Build, args = Args, + ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, + action = Action, copy = Copy}, {Frame, State}. @@ -155,6 +200,124 @@ call_param_sizer(Frame, J) -> {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. +handle_call(Unexpected, From, State) -> + ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]), + {noreply, State}. + + +handle_cast(Unexpected, State) -> + ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]), + {noreply, State}. + + +handle_info(Unexpected, State) -> + ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), + {noreply, State}. + + +handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, + State = #s{action = #w{id = ID}}) -> + NewState = engage(State); + {noreply, NewState}; + +handle_event(Event, State) -> + ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), + {noreply, State}. + + +code_change(_, State, _) -> + {ok, State}. + + +terminate(Reason, State) -> + ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), + wx:destroy(). + + +handle_troubling(State = #s{frame = Frame}, Info) -> + ok = wxFrame:raise(Frame), + ok = zxw:show_message(Frame, Info), + State. + + +engage(State = #s{j = J}) -> + case gd_con:chain_id() of + {ok, ChainID} -> engage(State, ChainID); + Error -> handle_troubling(State, Error) + end. + +engage(State = #s{fundef = {"init", init}, build = Build}, ChainID) -> + {CallerID, Nonce, TTL, GasPrice, Gas, Amount} = params(State), + Args = args(State), + case hz:contract_create_built(CallerID, + Nonce, Amount, TTL, Gas, GasPrice, + Build, InitArgs) of + {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); + Error -> handle_troubling(State, Error) + end; +engage(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID) -> + AACI = maps:get(aaci, AACI), + {PK, Nonce, TTL, GasP, Gas, Amount} = params(State), + Args = args(State), + case hz:contract_call(PK, Nonce, Gas, GasP, Amount, TTL, AACI, ConID, Name, Args) of + {ok, UnsignedTX} -> + case Type of + call -> do_call(State, ChainID, PK, UnsignedTX); + dryr -> do_dry_run(State, ConID, UnsignedTX) + end; + Error -> + handle_troubling(State, Error) + end. + + +% NEXT: Complete the signature and enter check_tx/2 + +deploy(State, ChainID, CallerID, CreateTX) -> + SignedTX = hz:sign_tx(CreateTX, SecKey, ChainID), + tell(info, "SignedTX: ~p", [SignedTX]), + case hz:post_tx(SignedTX) of + {ok, Data = #{"tx_hash" := TXHash}} -> + ok = tell("Contract deploy TX succeded with: ~p", [TXHash]), + do_deploy3(Data); + {ok, WTF} -> + gd_v_devman:trouble({error, WTF}); + Error -> + gd_v_devman:trouble(Error) + end. + +do_deploy3(#{"tx_hash" := TXHash}) -> + case hz:tx_info(TXHash) of + {ok, #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> + gd_v_devman:open_contract(ConID); + {error, "Tx not mined"} -> + gd_v_devman:trouble({tx_hash, TXHash}); + {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> + gd_v_devman:trouble({error, Reason}); + Error -> + gd_v_devman:trouble(Error) + end. + + +do_call(State, ChainID, CallerID, UnsignedTX) -> + case gd_con:sign_call(ChainID, CallerID, UnsignedTX) of + {ok, SignedTX} -> do_call(State, SignedTX); + Error -> handle_troubling(State, Error) + end. + +do_call(State, SignedTX) -> + case hz:post_tx(SignedTX) of + {ok, TX_Hash} -> + + +do_dry_run(State, ConID, TX) -> + case hz:dry_run(TX) of + {ok, Result} -> gd_v_devman:dryrun_result(ConID, Result); + Other -> gd_v_devmam:trouble({error, ConID, Other}) + end. + ok = gd_con:dry_run(ConID, TX), + State. + + textify({integer, _, _}) -> "int"; textify({boolean, _, _}) -> "bool"; textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index eaa98be..4944691 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -14,14 +14,9 @@ handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). +-include("gdl.hrl"). -% Widgets --record(w, - {name = none :: atom() | {FunName :: binary(), call | dryr}, - id = 0 :: integer(), - wx = none :: none | wx:wx_object()}). - % Contract functions in an ACI -record(f, {name = <<"">> :: binary(), @@ -316,108 +311,16 @@ style(#s{code = {_, Pages}}, Win, Event) -> tell("Received bogus style event.~nWin: ~p~nEvent: ~p", [Win, Event]) end. -clicked(State = #s{cons = {Consbook, Contracts}}, Name) -> - case wxNotebook:getSelection(Consbook) of - ?wxNOT_FOUND -> - ok = tell(warning, "Inconcievable! No notebook page is selected!"), - State; - Index -> - #c{id = ConID, build = #{aaci := AACI}} = lists:nth(Index + 1, Contracts), - - clicked2(State, Contract, Name) - end. - -clicked2(State, Contract, Name) -> - case gd_con:list_keys() of - {ok, 0, []} -> - handle_troubling(State, "No keys exist in the current wallet."); - {ok, Selected, Keys} -> - clicked3(State, Contract, Name, Selected, Keys); - error -> - handle_troubling(State, "No wallet is selected!") - end. - -clicked3(State = #s{frame = Frame, j = J}, Contract, FunDef, Selected, Keys) -> - #c{id = ConID, build = #{aaci := AACI}} = Contract, - ok = gd_con:make_call(FunDef, ConID, AACI), - State. - - - Dialog = wxDialog:new(Frame, ?wxID_ANY, Label), - Sizer = wxBoxSizer:new(?wxVERTICAL), - KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), - KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), - _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - ok = wxChoice:setSelection(KeyPicker, Selected - 1), - {ArgSz, ArgControls, Dimensions} = call_arg_sizer(Dialog, J, FunSpec), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(Dialog, J), - ButtSz = wxBoxSizer:new(?wxHORIZONTAL), - Affirm = wxButton:new(Dialog, ?wxID_OK), - Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), - _ = wxSizer:add(Sizer, KeySz, zxw:flags({base, 5})), - _ = wxSizer:add(Sizer, ArgSz, zxw:flags({wide, 5})), - _ = wxSizer:add(Sizer, ParamSz, zxw:flags({base, 5})), - _ = wxSizer:add(Sizer, ButtSz, zxw:flags({base, 5})), - ok = wxDialog:setSizer(Dialog, Sizer), - ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, Dimensions), - ok = wxDialog:center(Dialog), - Outcome = - case wxDialog:showModal(Dialog) of - ?wxID_OK -> - ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), - PK = unicode:characters_to_binary(ID), - Controls = - [{{"TTL", fun gt_0/1}, TTL_Tx}, - {{"Gas Price", fun gt_0/1}, GasP_Tx}, - {{"Gas", fun gt_0/1}, Gas_Tx}, - {{"Amount", fun gte_0/1}, Amount_Tx}], - case call_params(Controls) of - {ok, [TTL, GasP, Gas, Amount]} -> - {Message, CArgs} = extract_args(ArgControls), - ok = gd_v_devman:write_console(ConID, Message), - {ok, Nonce} = hz:next_nonce(PK), - CallParams = {PK, Nonce, TTL, GasP, Gas, Amount}, - {ok, CallParams, CArgs}; - E -> - E - end; - ?wxID_CANCEL -> - cancel +clicked(State = #s{cons = {Consbook, Contracts}}, FunDef) -> + ok = + case wxNotebook:getSelection(Consbook) of + ?wxNOT_FOUND -> + tell(warning, "Inconcievable! No deployed contract page is selected!"); + Index -> + #c{id = ConID, build = Build} = lists:nth(Index + 1, Contracts), + gd_con:prompt_call(FunDef, ConID, Build) end, - ok = wxDialog:destroy(Dialog), - case Outcome of - {ok, Params, Args} -> clicked4(State, Contract, Name, Params, Args); - cancel -> State; - Error -> handle_troubling(State, Error) - end. - - -clicked4(State, - #c{id = ConID, build = #{aaci := AACI}}, - {Name, Type}, - {PK, Nonce, TTL, GasP, Gas, Amt}, - Args) -> - case hz:contract_call(PK, Nonce, Gas, GasP, Amt, TTL, AACI, ConID, Name, Args) of - {ok, UnsignedTX} -> - case Type of - call -> do_call(State, ConID, PK, UnsignedTX); - dryr -> do_dry_run(State, ConID, UnsignedTX) - end; - Error -> - handle_troubling(State, Error), - State - end. - -do_call(State, ConID, CallerID, UnsignedTX) -> - ok = gd_con:sign_call(ConID, CallerID, UnsignedTX), - State. - -do_dry_run(State, ConID, TX) -> - ok = gd_con:dry_run(ConID, TX), State. @@ -562,82 +465,11 @@ deploy(State = #s{code = {Codebook, Pages}}) -> end. deploy2(State, Source) -> - case compile(Source) of -% TODO: Make hz accept either the aaci or the aci, preferring the aaci if present - {ok, Build} -> - {aaci, ContractName, Funs, _} = maps:get(aaci, Build), - ok = tell(info, "Deploying Contract: ~p", [ContractName]), - InitSpec = maps:get("init", Funs), - deploy3(State, InitSpec, Build); - Other -> - ok = tell(info, "Compilation Failed!~n~tp", [Other]), - State - end. - -deploy3(State, InitSpec, Build) -> - case gd_con:list_keys() of - {ok, 0, []} -> - handle_troubling(State, "No keys exist in the current wallet."); - {ok, Selected, Keys} -> - deploy4(State, InitSpec, Build, Selected, Keys); - error -> - handle_troubling(State, "No wallet is selected!") - end. - -deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, Selected, Keys) -> - Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Deploy Contract")), - Sizer = wxBoxSizer:new(?wxVERTICAL), - KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Key")}]), - KeyPicker = wxChoice:new(Dialog, ?wxID_ANY, [{choices, Keys}]), - _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - ok = wxChoice:setSelection(KeyPicker, Selected - 1), - {ArgSz, ArgControls, Dimensions} = call_arg_sizer(Dialog, J, InitSpec), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx} = call_param_sizer(Dialog, J), - ButtSz = wxBoxSizer:new(?wxHORIZONTAL), - Affirm = wxButton:new(Dialog, ?wxID_OK), - Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), - _ = wxSizer:add(Sizer, KeySz, zxw:flags({base, 5})), - _ = wxSizer:add(Sizer, ArgSz, zxw:flags({wide, 5})), - _ = wxSizer:add(Sizer, ParamSz, zxw:flags({base, 5})), - _ = wxSizer:add(Sizer, ButtSz, zxw:flags({base, 5})), - ok = wxDialog:setSizer(Dialog, Sizer), - ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, Dimensions), - ok = wxDialog:center(Dialog), - Outcome = - case wxDialog:showModal(Dialog) of - ?wxID_OK -> - ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), - PK = unicode:characters_to_binary(ID), - Controls = - [{{"TTL", fun gt_0/1}, TTL_Tx}, - {{"Gas Price", fun gt_0/1}, GasP_Tx}, - {{"Gas", fun gt_0/1}, Gas_Tx}, - {{"Amount", fun gte_0/1}, Amount_Tx}], - case call_params(Controls) of - {ok, [TTL, GasP, Gas, Amount]} -> - {Message, CArgs} = extract_args(ArgControls), - ok = tell(Message), - {ok, Nonce} = hz:next_nonce(PK), - DeployParams = {PK, Nonce, TTL, GasP, Gas, Amount}, - {ok, DeployParams, CArgs}; - E -> - E - end; - ?wxID_CANCEL -> - cancel + ok = + case compile(Source) of + {ok, Build} -> gd_con:prompt_call({"init", init}, init, Build); + Other -> tell(info, "Compilation Failed!~n~tp", [Other]) end, - ok = wxDialog:destroy(Dialog), - case Outcome of - {ok, Params, Args} -> deploy5(State, Build, Params, Args); - cancel -> State; - Error -> handle_troubling(State, Error) - end. - -deploy5(State, Build, Params, Args) -> - ok = gd_con:deploy(Build, Params, Args), State. @@ -669,7 +501,8 @@ open(State = #s{frame = Frame, j = J}) -> 1 -> hash; ?wxNOT_FOUND -> none end; - ?wxID_CANCEL -> cancel + ?wxID_CANCEL -> + cancel end, ok = wxDialog:destroy(Dialog), case Choice of diff --git a/src/gd_v_netman.erl b/src/gd_v_netman.erl index deeec13..4ae4abf 100644 --- a/src/gd_v_netman.erl +++ b/src/gd_v_netman.erl @@ -14,13 +14,9 @@ handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). +-include("gdl.hrl"). --record(w, - {name = none :: atom(), - id = 0 :: integer(), - wx = none :: none | wx:wx_object()}). - -record(s, {wx = none :: none | wx:wx_object(), frame = none :: none | wx:wx_object(), diff --git a/src/gd_v_wallman.erl b/src/gd_v_wallman.erl index 40c2d5e..c4e4f22 100644 --- a/src/gd_v_wallman.erl +++ b/src/gd_v_wallman.erl @@ -28,13 +28,9 @@ handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). +-include("gdl.hrl"). --record(w, - {name = none :: atom(), - id = 0 :: integer(), - wx = none :: none | wx:wx_object()}). - -record(s, {wx = none :: none | wx:wx_object(), frame = none :: none | wx:wx_object(), -- 2.30.2 From 9365c33351a257ed6f928a4ae27e01f13a9ff56e Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 6 Apr 2026 14:42:21 +0900 Subject: [PATCH 11/37] WIP --- src/gd_gui.erl | 25 ++---------- src/gd_lib.erl | 24 +++++++++++- src/gd_v_call.erl | 97 +++++++++++++++++++++++++++++++---------------- 3 files changed, 92 insertions(+), 54 deletions(-) diff --git a/src/gd_gui.erl b/src/gd_gui.erl index d8e92a8..f73dfd5 100644 --- a/src/gd_gui.erl +++ b/src/gd_gui.erl @@ -298,7 +298,7 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, #w{name = mnemonic} -> show_mnemonic(State); #w{name = rename} -> rename_key(State); #w{name = drop_key} -> drop_key(State); - #w{name = copy} -> copy(State); + #w{name = copy} -> copy_pk(State); #w{name = www} -> www(State); #w{name = send} -> spend(State); #w{name = grids} -> grids_dialogue(State); @@ -588,7 +588,7 @@ show_mnemonic(Selected, State = #s{frame = Frame, j = J, accounts = Accounts}) - ok = case wxDialog:showModal(Dialog) of ?wxID_CANCEL -> ok; - ?wxID_OK -> copy_to_clipboard(Mnemonic) + ?wxID_OK -> gd_lib:copy_to_clipboard(Mnemonic) end, ok = wxDialog:destroy(Dialog), State. @@ -656,28 +656,11 @@ drop_key(Selected, State = #s{frame = Frame, j = J, accounts = Accounts, prefs = State#s{prefs = NewPrefs}. -copy(State = #s{id = {_, #w{wx = ID_T}}}) -> +copy_pk(State = #s{id = {_, #w{wx = ID_T}}}) -> String = wxStaticText:getLabel(ID_T), - ok = copy_to_clipboard(String), + ok = gd_lib:copy_to_clipboard(String), State. -copy_to_clipboard(String) -> - CB = wxClipboard:get(), - case wxClipboard:open(CB) of - true -> - Text = wxTextDataObject:new([{text, String}]), - case wxClipboard:setData(CB, Text) of - true -> - R = wxClipboard:flush(CB), - log(info, "String copied to system clipboard. Flushed: ~p", [R]); - false -> - log(info, "Failed to copy to clipboard") - end, - ok = wxClipboard:close(CB); - false -> - log(info, "Failed to acquire the clipboard.") - end. - www(State = #s{id = {_, #w{wx = ID_T}}, j = J}) -> case wxStaticText:getLabel(ID_T) of diff --git a/src/gd_lib.erl b/src/gd_lib.erl index d288ca9..fffd704 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -7,7 +7,8 @@ -export([is_int/1, mono_text/2, mono_text/3, - button/2, button/3]). + button/2, button/3, + copy_to_clipboard/1]). -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). @@ -76,3 +77,24 @@ button(Parent, Label) -> button(Parent, Name, Label) -> Button = wxButton:new(Parent, ?wxID_ANY, [{label, Label}]), #w{name = Name, id = wxButton:getId(Button), wx = Button}. + + +-spec copy_to_clipboard(String) -> ok + when String :: unicode:charlist(). + +copy_to_clipboard(String) -> + CB = wxClipboard:get(), + case wxClipboard:open(CB) of + true -> + Text = wxTextDataObject:new([{text, String}]), + case wxClipboard:setData(CB, Text) of + true -> + R = wxClipboard:flush(CB), + log(info, "String copied to system clipboard. Flushed: ~p", [R]); + false -> + log(info, "Failed to copy to clipboard") + end, + ok = wxClipboard:close(CB); + false -> + log(info, "Failed to acquire the clipboard.") + end. diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index f316bc4..fe1548d 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -32,7 +32,9 @@ gas = #w{} :: #w{}, amount = #w{} :: #w{}, action = #w{} :: #w{}, + tx_data = none :: none | map(), tx_hash = #w{} :: #w{}, + tx_info = none :: none | hz:transaction(), out = #w{} :: #w{}, copy = #w{} :: #w{}}). @@ -117,10 +119,11 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - con_id = ConID, build = Build, args = Args, - ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, - action = Action, copy = Copy}, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + con_id = ConID, build = Build, + args = Args, keypicker = KeyPicker, + ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, + action = Action, copy = Copy}, {Frame, State}. @@ -217,9 +220,12 @@ handle_info(Unexpected, State) -> handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{action = #w{id = ID}}) -> - NewState = engage(State); + NewState = engage(State), {noreply, NewState}; - +handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, + State = #s{copy = #w{id = ID}}) -> + ok = copy(State), + {noreply, State}; handle_event(Event, State) -> ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. @@ -270,54 +276,81 @@ engage(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID end. -% NEXT: Complete the signature and enter check_tx/2 +params(#s{ttl = #w{wx = TTL}, + gasprice = #w{wx = GasPrice}, + gas = #w{wx = Gas}, + amount = #w{wx = Amount}, + }) -> + + +args(#s{args = ArgFields}) -> + deploy(State, ChainID, CallerID, CreateTX) -> - SignedTX = hz:sign_tx(CreateTX, SecKey, ChainID), - tell(info, "SignedTX: ~p", [SignedTX]), - case hz:post_tx(SignedTX) of - {ok, Data = #{"tx_hash" := TXHash}} -> - ok = tell("Contract deploy TX succeded with: ~p", [TXHash]), - do_deploy3(Data); - {ok, WTF} -> - gd_v_devman:trouble({error, WTF}); - Error -> - gd_v_devman:trouble(Error) + case gd_con:sign_tx(ChainID, CallerID, CreateTX) of + {ok, SignedTX} -> deploy2(State, SignedTX); + Error -> handle_troubling(State, Error) end. -do_deploy3(#{"tx_hash" := TXHash}) -> - case hz:tx_info(TXHash) of - {ok, #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> - gd_v_devman:open_contract(ConID); - {error, "Tx not mined"} -> - gd_v_devman:trouble({tx_hash, TXHash}); - {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> - gd_v_devman:trouble({error, Reason}); - Error -> - gd_v_devman:trouble(Error) +deploy2(State, SignedTX) -> + case hz:post_tx(SignedTX) of + {ok, Data} -> check_tx(State#s{tx_data = Data}); + {ok, WTF} -> handle_troubling(State, {error, WTF}); + Error -> handle_troubling(State, Error) end. do_call(State, ChainID, CallerID, UnsignedTX) -> case gd_con:sign_call(ChainID, CallerID, UnsignedTX) of - {ok, SignedTX} -> do_call(State, SignedTX); + {ok, SignedTX} -> do_call2(State, SignedTX); Error -> handle_troubling(State, Error) end. -do_call(State, SignedTX) -> +do_call2(State, SignedTX) -> case hz:post_tx(SignedTX) of - {ok, TX_Hash} -> - + {ok, Data} -> check_tx(SDtate = #s{tx_data = Data}); + Error -> handle_troubling(State, Error) + end. do_dry_run(State, ConID, TX) -> case hz:dry_run(TX) of {ok, Result} -> gd_v_devman:dryrun_result(ConID, Result); Other -> gd_v_devmam:trouble({error, ConID, Other}) end. - ok = gd_con:dry_run(ConID, TX), + + +check_tx(State = #s{tx_data = #{"tx_hash" := TXHash} = TXData, tx_info = none}) -> + ok = tell("TXData: ~p", [TXData]), + case hz:tx_info(TXHash) of + {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> + ok = gd_v_devman:open_contract(ConID), + update_info(State#s{tx_info = Info}); + {error, "Tx not mined"} -> + handle_troubling(State, {error, not_mined}); + {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> + handle_troubling(State, {error, Reason}); + Error -> + handle_troubling(State, Error) + end; +check_tx(State = #s{tx_info = TXInfo}) -> + ok = tell("Nothing to check"), State. +update_info(State = #s{tx_info = TXInfo, out = #w{wx = Out}}) -> + Formatted = io_lib:format("TXInfo: ~p~n", [TXInfo]), + ok = wxStaticText:setLabel(Out, Formatted), + State. + + +copy(State = #s{tx_info = none}) -> + ok; +copy(State = #s{out = #w{wx = Out}}) -> + Output = wxStaticText:getLabel(Out), + gd_lib:copy_to_clipboard(Output). + + + textify({integer, _, _}) -> "int"; textify({boolean, _, _}) -> "bool"; textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); -- 2.30.2 From acd84d65a8aa4b116addb3456ceb69e2e667a3f6 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 6 Apr 2026 17:28:31 +0900 Subject: [PATCH 12/37] WIP --- src/gd_v_call.erl | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index fe1548d..53b273f 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -27,6 +27,7 @@ fundef = none :: none | fun_def(), build = none :: none | map(), args = [] :: [#w{}], + kp = #w{} :: #w{}, ttl = #w{} :: #w{}, gasprice = #w{} :: #w{}, gas = #w{} :: #w{}, @@ -119,11 +120,11 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - con_id = ConID, build = Build, - args = Args, keypicker = KeyPicker, - ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, - action = Action, copy = Copy}, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + con_id = ConID, build = Build, + args = Args, kp = KeyPicker, + ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, + action = Action, copy = Copy}, {Frame, State}. @@ -276,12 +277,31 @@ engage(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID end. -params(#s{ttl = #w{wx = TTL}, - gasprice = #w{wx = GasPrice}, - gas = #w{wx = Gas}, - amount = #w{wx = Amount}, - }) -> +params(State = #s{kp = #w{wx = KeyPicker}}) -> + ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), + PK = unicode:characters_to_binary(ID), + case hz:next_nonce(PK) of + {ok, Nonce} -> params2(State, PK, Nonce); + Error -> handle_troubling(State, Error) + end. +params2(State, PK, Nonce) -> + Params = extract(State), +params2(#s{ttl = #w{wx = TTL_T}, + gasprice = #w{wx = GasPriceT}, + gas = #w{wx = GasT}, + amount = #w{wx = AmountT}}, + PK, + Nonce) -> + TTL = wxTextCtrl:getValue(TTL_T), + GasPrice = wxTextCtrl:getValue(GasPriceT), + +extract(State) -> extract(State, {none, none, none, none}). + +extract(State = #s{ttl = W}, {none, none, none, none}) -> +extract(State = #s{gasprice = W}, {TTL, none, none, none}) -> +extract(State = #s{gas = W}, {TTL, GP, none, none}) -> +extract(State = #s{amount = W}, {TTL, GP, Gas, none}) -> args(#s{args = ArgFields}) -> @@ -312,10 +332,11 @@ do_call2(State, SignedTX) -> Error -> handle_troubling(State, Error) end. + do_dry_run(State, ConID, TX) -> case hz:dry_run(TX) of - {ok, Result} -> gd_v_devman:dryrun_result(ConID, Result); - Other -> gd_v_devmam:trouble({error, ConID, Other}) + {ok, Result} -> update_info(State#s{tx_info = Result}); + Other -> handle_troubling(State, {error, ConID, Other}) end. @@ -332,7 +353,7 @@ check_tx(State = #s{tx_data = #{"tx_hash" := TXHash} = TXData, tx_info = none}) Error -> handle_troubling(State, Error) end; -check_tx(State = #s{tx_info = TXInfo}) -> +check_tx(State) -> ok = tell("Nothing to check"), State. -- 2.30.2 From a4db8d9a95c9d11790b355d5c94b5858b4f3508f Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 7 Apr 2026 18:40:17 +0900 Subject: [PATCH 13/37] WIP --- src/gd_lib.erl | 2 +- src/gd_v_call.erl | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/gd_lib.erl b/src/gd_lib.erl index fffd704..f4ef441 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -54,7 +54,7 @@ mono_text(Parent, Name, Value) -> ok = case wxStaticText:setFont(Text, Font) of true -> ok; - false -> log(info, "wxStaticText ~p is already monospace.", [Text) + false -> tell(info, "wxStaticText ~p is already monospace.", [Text) end, #w{name = Name, id = wxStaticText:getId(Text), wx = Text}. diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 53b273f..401e114 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -28,6 +28,7 @@ build = none :: none | map(), args = [] :: [#w{}], kp = #w{} :: #w{}, + params = [] :: [param()], ttl = #w{} :: #w{}, gasprice = #w{} :: #w{}, gas = #w{} :: #w{}, @@ -43,6 +44,7 @@ -type fun_name() :: string(). -type fun_type() :: call | dryr | init. -type fun_def() :: {fun_name(), fun_type()}. +-type param() :: {Label :: string(), Check :: fun(), #w{}}. %%% Interface @@ -247,7 +249,7 @@ handle_troubling(State = #s{frame = Frame}, Info) -> State. -engage(State = #s{j = J}) -> +engage(State) -> case gd_con:chain_id() of {ok, ChainID} -> engage(State, ChainID); Error -> handle_troubling(State, Error) @@ -285,23 +287,28 @@ params(State = #s{kp = #w{wx = KeyPicker}}) -> Error -> handle_troubling(State, Error) end. -params2(State, PK, Nonce) -> - Params = extract(State), params2(#s{ttl = #w{wx = TTL_T}, gasprice = #w{wx = GasPriceT}, gas = #w{wx = GasT}, amount = #w{wx = AmountT}}, PK, Nonce) -> - TTL = wxTextCtrl:getValue(TTL_T), - GasPrice = wxTextCtrl:getValue(GasPriceT), + ToExtract = + [{ttl, fun gte_0/1, TTL_T}, + {gasprice, fun gt_0/1, GasPriceT}, + {gas, fun gt_0/1, GasT}, + {amount, fun gt_0/1, AmountT}], + case lists:foldl(fun extract/2, {ok, []}, ToCheck) of + {ok, [TTL, GasPrice, Gas, Amount]} -> + {error, Out} -> + end. -extract(State) -> extract(State, {none, none, none, none}). +extract({Name, Check, Widget}, {Status, Out}) -> + case Check(wxTextCtrl:getValue(Widget)) of + {ok, Value} -> {Status, [Value | Out]}; + Error -> {error, [{Name, Error}, Out]} + end. -extract(State = #s{ttl = W}, {none, none, none, none}) -> -extract(State = #s{gasprice = W}, {TTL, none, none, none}) -> -extract(State = #s{gas = W}, {TTL, GP, none, none}) -> -extract(State = #s{amount = W}, {TTL, GP, Gas, none}) -> args(#s{args = ArgFields}) -> -- 2.30.2 From fadc252fb21bc48a4a32275f41e9cf54a21549c5 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 27 Apr 2026 19:00:47 +0900 Subject: [PATCH 14/37] WIP --- src/gd_v_call.erl | 133 +++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 401e114..0dab625 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -91,23 +91,26 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Signature Key")}]), KeyPicker = wxChoice:new(Frame, ?wxID_ANY, [{choices, Keys}]), + ok = wxChoice:setSelection(KeyPicker, Selected), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - {ArgSz, Args} = call_arg_sizer(Frame, J, FunSpec), - {ParamSz, TTL_T, GasPriceT, GasT, AmountT} = call_param_sizer(Frame, J), + {ArgSz, Args, Dimensions} = call_arg_sizer(Frame, J, FunSpec), + {ParamSz, Params} = call_param_sizer(Frame, J), Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), TX_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Transaction Info")}]), - TX_Hash = #w{wx = HashTxt} = gd_lib:mono_text(TX_Sz, tx_hash), + TX_Data = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), + TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), + TX_Info = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), Line = wxStaticLine:new(TX_Sz, [{style, ?wxLI_HORIZONTAL}]), Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz, out), Copy = #w{wx = CopyBn} = gd_lib:button(Frame, J("Copy")), - _ = wxStaticBoxSizer:add(TX_Sz, HashTxt, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({wide, 5})), _ = wxSizer:add(MainSz, ArgSz, zxw:flags({wide, 5})), _ = wxSizer:add(MainSz, KeySz, zxw:flags({wide, 5})), @@ -122,11 +125,12 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - con_id = ConID, build = Build, - args = Args, kp = KeyPicker, - ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, - action = Action, copy = Copy}, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + con_id = ConID, build = Build, + args = Args, kp = KeyPicker, params = Params, + action = Action, + tx_data = TX_Data, tx_hash = TX_Hash, tx_info = TX_Info, + out = Out, copy = Copy}, {Frame, State}. @@ -182,28 +186,33 @@ call_param_sizer(Frame, J) -> GridSz = wxFlexGridSizer:new(2, 4, 4), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), - TTL_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), - ok = wxTextCtrl:setValue(TTL_Tx, integer_to_list(DefTTL)), - GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), - GasP_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), - ok = wxTextCtrl:setValue(GasP_Tx, integer_to_list(DefGasP)), - Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), - Gas_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), - ok = wxTextCtrl:setValue(Gas_Tx, integer_to_list(DefGas)), - Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), - Amount_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), - ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), + TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), + TTL_T = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(TTL_T, integer_to_list(DefTTL)), + GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), + GasP_T = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(GasP_T, integer_to_list(DefGasP)), + Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), + Gas_T = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Gas_T, integer_to_list(DefGas)), + Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), + Amount_T = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Amount_T, integer_to_list(DefAmount)), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_T, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_T, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_T, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_T, zxw:flags({wide, 5})), _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. + Params = + [{ "TTL", fun gte_0/1, TTL_T}, + {J("Gas Price"), fun gt_0/1, GasP_T}, + {J("Gas") , fun gt_0/1, Gas_T}, + {J("TX Amount"), fun gt_0/1, Amount_T}], + {ParamSz, Params}. handle_call(Unexpected, From, State) -> @@ -251,34 +260,41 @@ handle_troubling(State = #s{frame = Frame}, Info) -> engage(State) -> case gd_con:chain_id() of - {ok, ChainID} -> engage(State, ChainID); + {ok, ChainID} -> engage2(State, ChainID); Error -> handle_troubling(State, Error) end. -engage(State = #s{fundef = {"init", init}, build = Build}, ChainID) -> - {CallerID, Nonce, TTL, GasPrice, Gas, Amount} = params(State), - Args = args(State), - case hz:contract_create_built(CallerID, - Nonce, Amount, TTL, Gas, GasPrice, - Build, InitArgs) of +engage2(State, ChainID) -> + case params(State) of + {ok, Params} -> engage3(State, ChainID, Params); + Error -> handle_troubling(State, Error) + end. + +engage3(State, ChainID, Params) -> + case args(State) of + {ok, Args} -> engage4(State, ChainID, Params, {sophia, Args}); + Error -> handle_troubling(State, Error) + end. + +engage4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> + {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, + case hz:contract_create_built(CallerID, Nonce, Gas, GP, Amount, TTL, Build, Args) of {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; -engage(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID) -> - AACI = maps:get(aaci, AACI), - {PK, Nonce, TTL, GasP, Gas, Amount} = params(State), - Args = args(State), - case hz:contract_call(PK, Nonce, Gas, GasP, Amount, TTL, AACI, ConID, Name, Args) of +engage4(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID, Params, Args) -> + {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, + AACI = maps:get(aaci, Build), + case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of {ok, UnsignedTX} -> case Type of - call -> do_call(State, ChainID, PK, UnsignedTX); + call -> do_call(State, ChainID, CallerID, UnsignedTX); dryr -> do_dry_run(State, ConID, UnsignedTX) end; Error -> handle_troubling(State, Error) end. - params(State = #s{kp = #w{wx = KeyPicker}}) -> ID = wxChoice:getString(KeyPicker, wxChoice:getSelection(KeyPicker)), PK = unicode:characters_to_binary(ID), @@ -287,20 +303,10 @@ params(State = #s{kp = #w{wx = KeyPicker}}) -> Error -> handle_troubling(State, Error) end. -params2(#s{ttl = #w{wx = TTL_T}, - gasprice = #w{wx = GasPriceT}, - gas = #w{wx = GasT}, - amount = #w{wx = AmountT}}, - PK, - Nonce) -> - ToExtract = - [{ttl, fun gte_0/1, TTL_T}, - {gasprice, fun gt_0/1, GasPriceT}, - {gas, fun gt_0/1, GasT}, - {amount, fun gt_0/1, AmountT}], - case lists:foldl(fun extract/2, {ok, []}, ToCheck) of - {ok, [TTL, GasPrice, Gas, Amount]} -> - {error, Out} -> +params2(#s{params = Params}, PK, Nonce) -> + case lists:foldl(fun extract/2, {ok, []}, Params) of + {ok, [TTL, GP, Gas, Amount]} -> {ok, {PK, Nonce, TTL, GP, Gas, Amount}}; + Error -> Error end. extract({Name, Check, Widget}, {Status, Out}) -> @@ -310,7 +316,12 @@ extract({Name, Check, Widget}, {Status, Out}) -> end. +% TODO: Put some basic checking in here, like for blank strings, at least. +% It should be possible to perform type/parse checks over this since we have +% access to the AACI. But not today. args(#s{args = ArgFields}) -> + Values = [wxTextCtrl:getValue(W) || #w{wx = W} <- ArgFields], + {ok, Values}. deploy(State, ChainID, CallerID, CreateTX) -> -- 2.30.2 From 24ce75f520cff148a119119cf5eb6f22420637ea Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 28 Apr 2026 14:15:28 +0900 Subject: [PATCH 15/37] WIP --- src/gd_con.erl | 42 ++++++++++++++++--------------------- src/gd_lib.erl | 7 ++++--- src/gd_v_call.erl | 53 +++++++++++------------------------------------ 3 files changed, 34 insertions(+), 68 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index b26f0bb..361c2ba 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -16,7 +16,7 @@ refresh/0, nonce/1, spend/1, chain_id/0, grids/1, sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, - prompt_call/3, + deploy/1, prompt_call/3, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). @@ -158,7 +158,7 @@ spend(TX) -> when ID :: binary(). chain_id() -> - gen_server:cast(?MODULE, {chain_id, ID}). + gen_server:cast(?MODULE, chain_id). -spec grids(string()) -> ok. @@ -192,28 +192,18 @@ sign_tx(Request) -> when ChainID :: binary(), PubKey :: gajudesk:id(), TX :: binary(), - Result :: {ok, SignedTX :: binary()}, + Result :: {ok, SignedTX :: binary()} | {error, Reason :: term()}. sign_call(ChainID, PubKey, TX) -> gen_server:call(?MODULE, {sign_call, ChainID, PubKey, TX}). --spec deploy(Build, Params, InitArgs) -> Result - when Build :: map(), - Params :: {PK :: gajudesk:id(), - Nonce :: non_neg_integer(), - TTL :: pos_integer(), - GasP :: pos_integer(), - Gas :: pos_integer(), - Amount :: pos_integer()}, - InitArgs :: [Arg :: string()], - Result :: {ok, TX_Hash :: gajudesk:id()} - | {error, Reason}, - Reason :: term(). % FIXME +-spec deploy(Build) -> ok + when Build :: map(). -deploy(Build, Params, InitArgs) -> - gen_server:cast(?MODULE, {deploy, Build, Params, InitArgs}). +deploy(Build) -> + gen_server:cast(?MODULE, {deploy, Build}). -spec prompt_call(FunDef, ConID, Build) -> ok @@ -406,9 +396,9 @@ handle_call(list_keys, _, State) -> handle_call({nonce, ID}, _, State) -> Response = do_nonce(ID), {reply, Response, State}; -handle_call({chain_id, State) -> +handle_call(chain_id, _, State) -> Response = do_chain_id(State), - {reply, Response, NewState}; + {reply, Response, State}; handle_call({sign_call, ChainID, PubKey, TX}, _, State) -> Response = do_sign_call(State, ChainID, PubKey, TX), {reply, Response, State}; @@ -479,10 +469,10 @@ handle_cast({sign_binary, Request}, State) -> handle_cast({sign_tx, Request}, State) -> ok = do_sign_tx(Request, State), {noreply, State}; -handle_cast({deploy, Build, Params, InitArgs}, State) -> - ok = do_deploy(Build, Params, InitArgs, State), +handle_cast({deploy, Build}, State) -> + ok = do_deploy(Build, State), {noreply, State}; -handle_cast({prompt_call, FunDef, ConID, Build}) -> +handle_cast({prompt_call, FunDef, ConID, Build}, State) -> NewState = do_prompt_call(FunDef, ConID, Build, State), {noreply, NewState}; handle_cast({make_key, Name, Seed, Encoding, Transform}, State) -> @@ -594,7 +584,7 @@ task_data(gd_v_devman, #s{}) -> %%% Network operations % NOTE: This is temporary. As GD becomes more chain aware this will move. -do_chain_id(#s{wallet = #wallet{chain_id = ChainID}) -> +do_chain_id(#s{wallet = #wallet{chain_id = ChainID}}) -> {ok, ChainID}; do_chain_id(_) -> {error, no_chain}. @@ -862,6 +852,10 @@ do_network(#s{wallet = #wallet{chain_id = ChainID}}) -> {ok, ChainID}. +do_deploy(Build, State) -> + do_prompt_call({"init", init}, none, Build, State). + + do_prompt_call(FunDef, ConID, Build, State = #s{tasks = Tasks, prefs = Prefs}) -> Name = {ConID, FunDef}, case do_list_keys(State) of @@ -872,7 +866,7 @@ do_prompt_call(FunDef, ConID, Build, State = #s{tasks = Tasks, prefs = Prefs}) - State; false -> CallPrefs = maps:get(gd_v_call, Prefs, #{}), - Win = gd_v_call:start_link({CallPrefs, FunDef, ConID, Build, Selected, Keys}), + Win = gd_v_call:start_link({CallPrefs, FunDef, ConID, Build, Selected, KeyIDs}), PID = wx_object:get_pid(Win), Mon = monitor(process, PID), UI = #ui{name = Name, pid = PID, wx = Win, mon = Mon}, diff --git a/src/gd_lib.erl b/src/gd_lib.erl index f4ef441..96ec690 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -5,6 +5,7 @@ -module(gd_lib). -vsn("0.8.1"). +-include_lib("wx/include/wx.hrl"). -export([is_int/1, mono_text/2, mono_text/3, button/2, button/3, @@ -42,7 +43,7 @@ mono_text(Parent, Name) -> Name :: term(), Value :: string(), StaticText :: #w{}. -@doc +%% @doc %% Creats a monospace font static text field with the given value. %% This exists so that I don't have to remember the difference between how to create a styled %% wxStaticText vs wxTextCtrl (which has to do it in a weird way because it has a much richer @@ -50,11 +51,11 @@ mono_text(Parent, Name) -> mono_text(Parent, Name, Value) -> Text = wxStaticText:new(Parent, ?wxID_ANY, Value), - Font = wxFont:new(10, ?wxFONTFAMILY_TELETYPE, ?wxFONT_STYLE_NORMAL, ?wxFONT_WEIGHT_NORMAL), + Font = wxFont:new(10, ?wxFONTFAMILY_TELETYPE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), ok = case wxStaticText:setFont(Text, Font) of true -> ok; - false -> tell(info, "wxStaticText ~p is already monospace.", [Text) + false -> tell(info, "wxStaticText ~p is already monospace.", [Text]) end, #w{name = Name, id = wxStaticText:getId(Text), wx = Text}. diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 0dab625..26d1528 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -100,14 +100,17 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), TX_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Transaction Info")}]), - TX_Data = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), - TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), - TX_Info = #w{wx = HashT} = gd_lib:mono_text(TX_Sz, tx_hash), + TX_Sz_Box = wxStaticBoxSizer:getStaticBox(TX_Sz), + TX_Data = #w{wx = DataT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), + TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), + TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), Line = wxStaticLine:new(TX_Sz, [{style, ?wxLI_HORIZONTAL}]), - Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz, out), + Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out), Copy = #w{wx = CopyBn} = gd_lib:button(Frame, J("Copy")), + _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({wide, 5})), @@ -282,7 +285,7 @@ engage4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Arg {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; -engage4(State = #s{con_id = ConID, build = Build, fundef = {Name, Type}}, ChainID, Params, Args) -> +engage4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, AACI = maps:get(aaci, Build), case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of @@ -333,7 +336,7 @@ deploy(State, ChainID, CallerID, CreateTX) -> deploy2(State, SignedTX) -> case hz:post_tx(SignedTX) of {ok, Data} -> check_tx(State#s{tx_data = Data}); - {ok, WTF} -> handle_troubling(State, {error, WTF}); +% {ok, WTF} -> handle_troubling(State, {error, WTF}); Error -> handle_troubling(State, Error) end. @@ -346,7 +349,7 @@ do_call(State, ChainID, CallerID, UnsignedTX) -> do_call2(State, SignedTX) -> case hz:post_tx(SignedTX) of - {ok, Data} -> check_tx(SDtate = #s{tx_data = Data}); + {ok, Data} -> check_tx(State = #s{tx_data = Data}); Error -> handle_troubling(State, Error) end. @@ -382,9 +385,9 @@ update_info(State = #s{tx_info = TXInfo, out = #w{wx = Out}}) -> State. -copy(State = #s{tx_info = none}) -> +copy(#s{tx_info = none}) -> ok; -copy(State = #s{out = #w{wx = Out}}) -> +copy(#s{out = #w{wx = Out}}) -> Output = wxStaticText:getLabel(Out), gd_lib:copy_to_clipboard(Output). @@ -399,38 +402,6 @@ textify({T, _, _}) when is_list(T) -> T; textify({T, _, _}) -> io_lib:format("~tp", [T]). -extract_args(Controls) -> - extract_args(Controls, []). - -extract_args([], Acc) -> - pack_args(Acc); -extract_args([{Name, Control} | T], Acc) -> - String = wxTextCtrl:getValue(Control), - extract_args(T, [{Name, String} | Acc]). - -pack_args(Args) -> - pack_args(Args, [], []). - -pack_args([], M, A) -> - Message = unicode:characters_to_list(["Call Args:\n", M]), - {Message, A}; -pack_args([{N, S} | T], M, A) -> - pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). - -call_params(Controls) -> - call_params(Controls, {[], []}). - -call_params([], {Acc, []}) -> - {ok, lists:reverse(Acc)}; -call_params([], {_, Errors}) -> - {error, lists:reverse(Errors)}; -call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> - String = wxTextCtrl:getValue(Control), - case Validate(String) of - {ok, Value} -> call_params(T, {[Value | Acc], Errors}); - {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) - end. - gt_0(S) -> C = "Must be an integer greater than 0", R = -- 2.30.2 From 7008195090f276cdefd703401ee2d0ed168fdc4d Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 28 Apr 2026 14:39:37 +0900 Subject: [PATCH 16/37] WIP --- src/gd_v_call.erl | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 26d1528..248548e 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -104,24 +104,25 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> TX_Data = #w{wx = DataT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), - Line = wxStaticLine:new(TX_Sz, [{style, ?wxLI_HORIZONTAL}]), + Line = wxStaticLine:new(TX_Sz_Box, [{style, ?wxLI_HORIZONTAL}]), Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out), - Copy = #w{wx = CopyBn} = gd_lib:button(Frame, J("Copy")), + Copy = #w{wx = CopyBn} = gd_lib:button(TX_Sz_Box, J("Copy")), - _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({base, 5})), _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ArgSz, zxw:flags({wide, 5})), - _ = wxSizer:add(MainSz, KeySz, zxw:flags({wide, 5})), - _ = wxSizer:add(MainSz, ParamSz, zxw:flags({wide, 5})), - _ = wxSizer:add(MainSz, ActionBn, zxw:flags({wide, 5})), - _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, KeySz, zxw:flags({base, 5})), + _ = wxSizer:add(MainSz, ParamSz, zxw:flags({base, 5})), + _ = wxSizer:add(MainSz, ActionBn, zxw:flags({base, 5})), + _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({base, 5})), _ = wxFrame:setSizer(Frame, MainSz), + _ = wxFrame:setSize(Frame, Dimensions), _ = wxSizer:layout(MainSz), ok = gd_v:safe_size(Frame, Prefs), ok = wxFrame:connect(Frame, close_window), -- 2.30.2 From 0a671e7c9c386c904e1949061a81b29fea33e9a3 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 28 Apr 2026 18:46:43 +0900 Subject: [PATCH 17/37] WIP --- src/gd_v_call.erl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 248548e..f1009e6 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -124,7 +124,6 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> _ = wxFrame:setSizer(Frame, MainSz), _ = wxFrame:setSize(Frame, Dimensions), _ = wxSizer:layout(MainSz), - ok = gd_v:safe_size(Frame, Prefs), ok = wxFrame:connect(Frame, close_window), ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), @@ -171,11 +170,12 @@ call_sizer(Frame, J, CallArgs) -> {Name, C} end, Controls = lists:map(AddArg, CallArgs), - {CallSz, Controls, {600, 700}}. + {CallSz, Controls, {500, 900}}. return_sizer(Frame, J, ReturnType) -> ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Return Type")}]), - Return = wxStaticText:new(Frame, ?wxID_ANY, textify(ReturnType)), + ReturnSzBox = wxStaticBoxSizer:getStaticBox(ReturnSz), + Return = wxStaticText:new(ReturnSzBox, ?wxID_ANY, textify(ReturnType)), _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), ReturnSz. @@ -242,6 +242,9 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{copy = #w{id = ID}}) -> ok = copy(State), {noreply, State}; +handle_event(#wx{event = #wxClose{}}, State = #s{frame = Frame}) -> + ok = wxWindow:destroy(Frame), + {noreply, State}; handle_event(Event, State) -> ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. -- 2.30.2 From d1ee4c6a2440f44cf9cb64f5c0c8c28f0d766c4e Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 29 Apr 2026 12:55:26 +0900 Subject: [PATCH 18/37] WIP --- include/gdl.hrl | 2 +- src/gd_con.erl | 5 +++-- src/gd_v_call.erl | 30 ++++++++++++++++++------------ src/gd_v_devman.erl | 4 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/gdl.hrl b/include/gdl.hrl index 0b2f1cc..45d951d 100644 --- a/include/gdl.hrl +++ b/include/gdl.hrl @@ -1,5 +1,5 @@ % Widgets -record(w, - {name = none :: atom() | {FunName :: binary(), call | dryr}, + {name = none :: string() | atom() | {FunName :: binary(), call | dryr}, id = 0 :: integer(), wx = none :: none | wx:wx_object()}). diff --git a/src/gd_con.erl b/src/gd_con.erl index 361c2ba..a26c234 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -158,7 +158,7 @@ spend(TX) -> when ID :: binary(). chain_id() -> - gen_server:cast(?MODULE, chain_id). + gen_server:call(?MODULE, chain_id). -spec grids(string()) -> ok. @@ -866,7 +866,8 @@ do_prompt_call(FunDef, ConID, Build, State = #s{tasks = Tasks, prefs = Prefs}) - State; false -> CallPrefs = maps:get(gd_v_call, Prefs, #{}), - Win = gd_v_call:start_link({CallPrefs, FunDef, ConID, Build, Selected, KeyIDs}), + Args = {CallPrefs, FunDef, ConID, Build, Selected, KeyIDs}, + Win = gd_v_call:start_link(Args), PID = wx_object:get_pid(Win), Mon = monitor(process, PID), UI = #ui{name = Name, pid = PID, wx = Win, mon = Mon}, diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index f1009e6..b86209b 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -71,7 +71,7 @@ start_link(Args) -> wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). -init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> +init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), @@ -91,7 +91,9 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Signature Key")}]), KeyPicker = wxChoice:new(Frame, ?wxID_ANY, [{choices, Keys}]), - ok = wxChoice:setSelection(KeyPicker, Selected), + KP = #w{name = key_picker, id = wxChoice:getId(KeyPicker), wx = KeyPicker}, + ZeroBasedSelected = Selected - 1, + ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), {ArgSz, Args, Dimensions} = call_arg_sizer(Frame, J, FunSpec), @@ -105,7 +107,7 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), Line = wxStaticLine:new(TX_Sz_Box, [{style, ?wxLI_HORIZONTAL}]), - Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out), + Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out), Copy = #w{wx = CopyBn} = gd_lib:button(TX_Sz_Box, J("Copy")), _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({base, 5})), @@ -128,12 +130,12 @@ init({Prefs, {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - con_id = ConID, build = Build, - args = Args, kp = KeyPicker, params = Params, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + fundef = FunDef, con_id = ConID, build = Build, + args = Args, kp = KP, params = Params, action = Action, tx_data = TX_Data, tx_hash = TX_Hash, tx_info = TX_Info, - out = Out, copy = Copy}, + out = Out, copy = Copy}, {Frame, State}. @@ -149,7 +151,7 @@ call_sizer(Frame, J, []) -> CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), Args = wxStaticText:new(Frame, ?wxID_ANY, ["[", J("No Args"), "]"]), _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), - {CallSz, [], {500, 500}}; + {CallSz, [], {500, 700}}; call_sizer(Frame, J, CallArgs) -> ScrollWin = wxScrolledWindow:new(Frame), ScrollSz = wxBoxSizer:new(?wxVERTICAL), @@ -167,7 +169,7 @@ call_sizer(Frame, J, CallArgs) -> C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), - {Name, C} + #w{name = Name, id = wxTextCtrl:getId(C), wx = C} end, Controls = lists:map(AddArg, CallArgs), {CallSz, Controls, {500, 900}}. @@ -215,7 +217,7 @@ call_param_sizer(Frame, J) -> [{ "TTL", fun gte_0/1, TTL_T}, {J("Gas Price"), fun gt_0/1, GasP_T}, {J("Gas") , fun gt_0/1, Gas_T}, - {J("TX Amount"), fun gt_0/1, Amount_T}], + {J("TX Amount"), fun gte_0/1, Amount_T}], {ParamSz, Params}. @@ -272,18 +274,21 @@ engage(State) -> end. engage2(State, ChainID) -> + tell(info, "ChainID: ~p", [ChainID]), case params(State) of {ok, Params} -> engage3(State, ChainID, Params); Error -> handle_troubling(State, Error) end. engage3(State, ChainID, Params) -> + tell(info, "Params: ~p", [Params]), case args(State) of {ok, Args} -> engage4(State, ChainID, Params, {sophia, Args}); Error -> handle_troubling(State, Error) end. engage4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> + tell(info, "Args: ~p", [Args]), {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, case hz:contract_create_built(CallerID, Nonce, Gas, GP, Amount, TTL, Build, Args) of {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); @@ -332,7 +337,7 @@ args(#s{args = ArgFields}) -> deploy(State, ChainID, CallerID, CreateTX) -> - case gd_con:sign_tx(ChainID, CallerID, CreateTX) of + case gd_con:sign_call(ChainID, CallerID, CreateTX) of {ok, SignedTX} -> deploy2(State, SignedTX); Error -> handle_troubling(State, Error) end. @@ -378,7 +383,8 @@ check_tx(State = #s{tx_data = #{"tx_hash" := TXHash} = TXData, tx_info = none}) Error -> handle_troubling(State, Error) end; -check_tx(State) -> +check_tx(State = #s{tx_data = TXData}) -> + tell(info, "TXData: ~p", [TXData]), ok = tell("Nothing to check"), State. diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 4944691..cd2d7e4 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -798,8 +798,8 @@ load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j _ = wxSizer:add(ConsSz, ConsTx, zxw:flags(wide)), _ = wxSizer:add(ProgSz, CodeSz, [{proportion, 3}, {flag, ?wxEXPAND}]), _ = wxSizer:add(ProgSz, ScrollWin, [{proportion, 1}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(PageSz, ProgSz, [{proportion, 3}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(PageSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(PageSz, ProgSz, [{proportion, 3}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(PageSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND}]), {Out, IFaces, Build, NewButtons} = case compile(Source) of {ok, Output} -> -- 2.30.2 From ac18ecc916e03f789fcaadcb85b485230db2c824 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Fri, 1 May 2026 14:03:07 +0900 Subject: [PATCH 19/37] WIP: De-kajiggering --- src/gd_lib.erl | 11 +++++--- src/gd_v_call.erl | 68 ++++++++++++++++++++++++++------------------- src/gd_v_devman.erl | 39 ++++++++++---------------- 3 files changed, 61 insertions(+), 57 deletions(-) diff --git a/src/gd_lib.erl b/src/gd_lib.erl index 96ec690..a8512eb 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -7,7 +7,7 @@ -include_lib("wx/include/wx.hrl"). -export([is_int/1, - mono_text/2, mono_text/3, + mono_text/2, mono_text/3, mono_text/4, button/2, button/3, copy_to_clipboard/1]). @@ -50,14 +50,17 @@ mono_text(Parent, Name) -> %% notion of text styling). mono_text(Parent, Name, Value) -> - Text = wxStaticText:new(Parent, ?wxID_ANY, Value), + mono_text(Parent, Name, Value, []). + +mono_text(Parent, Name, Value, Options) -> + Text = wxTextCtrl:new(Parent, ?wxID_ANY, [{value, Value} | Options]), Font = wxFont:new(10, ?wxFONTFAMILY_TELETYPE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), ok = - case wxStaticText:setFont(Text, Font) of + case wxTextCtrl:setFont(Text, Font) of true -> ok; false -> tell(info, "wxStaticText ~p is already monospace.", [Text]) end, - #w{name = Name, id = wxStaticText:getId(Text), wx = Text}. + #w{name = Name, id = wxTextCtrl:getId(Text), wx = Text}. -spec button(Parent, Label) -> Button diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index b86209b..9d63721 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -96,18 +96,21 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - {ArgSz, Args, Dimensions} = call_arg_sizer(Frame, J, FunSpec), + {ArgSz, Args, HasArgs} = call_arg_sizer(Frame, J, FunSpec), {ParamSz, Params} = call_param_sizer(Frame, J), Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), TX_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Transaction Info")}]), TX_Sz_Box = wxStaticBoxSizer:getStaticBox(TX_Sz), - TX_Data = #w{wx = DataT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), - TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), - TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_hash), + TxStyle = [{style, ?wxTE_READONLY}], + TX_Data = #w{wx = DataT} = gd_lib:mono_text(TX_Sz_Box, tx_data, "", TxStyle), + TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash, "", TxStyle), + TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_info, "", TxStyle), + Line = wxStaticLine:new(TX_Sz_Box, [{style, ?wxLI_HORIZONTAL}]), - Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out), + OutStyle = [{style, ?wxTE_MULTILINE bor ?wxTE_READONLY}], + Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out, "", OutStyle), Copy = #w{wx = CopyBn} = gd_lib:button(TX_Sz_Box, J("Copy")), _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({base, 5})), @@ -117,14 +120,19 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({base, 5})), - _ = wxSizer:add(MainSz, ArgSz, zxw:flags({wide, 5})), + ArgSzArgs = + case HasArgs of + true -> {wide, 5}; + false -> {base, 5} + end, + _ = wxSizer:add(MainSz, ArgSz, zxw:flags(ArgSzArgs)), _ = wxSizer:add(MainSz, KeySz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ParamSz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ActionBn, zxw:flags({base, 5})), - _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({base, 5})), + _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({wide, 5})), _ = wxFrame:setSizer(Frame, MainSz), - _ = wxFrame:setSize(Frame, Dimensions), + _ = wxFrame:setSize(Frame, {900, 900}), _ = wxSizer:layout(MainSz), ok = wxFrame:connect(Frame, close_window), ok = wxFrame:connect(Frame, command_button_clicked), @@ -141,17 +149,17 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> call_arg_sizer(Frame, J, {CallArgs, ReturnType}) -> SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), - {CallSz, CallControls, Dimensions} = call_sizer(Frame, J, CallArgs), + {CallSz, CallControls, HasArgs} = call_sizer(Frame, J, CallArgs), ReturnSz = return_sizer(Frame, J, ReturnType), _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), - {SpecSz, CallControls, Dimensions}. + {SpecSz, CallControls, HasArgs}. call_sizer(Frame, J, []) -> CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), Args = wxStaticText:new(Frame, ?wxID_ANY, ["[", J("No Args"), "]"]), _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), - {CallSz, [], {500, 700}}; + {CallSz, [], false}; call_sizer(Frame, J, CallArgs) -> ScrollWin = wxScrolledWindow:new(Frame), ScrollSz = wxBoxSizer:new(?wxVERTICAL), @@ -172,7 +180,7 @@ call_sizer(Frame, J, CallArgs) -> #w{name = Name, id = wxTextCtrl:getId(C), wx = C} end, Controls = lists:map(AddArg, CallArgs), - {CallSz, Controls, {500, 900}}. + {CallSz, Controls, true}. return_sizer(Frame, J, ReturnType) -> ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Return Type")}]), @@ -195,28 +203,28 @@ call_param_sizer(Frame, J) -> TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), TTL_T = wxTextCtrl:new(Frame, ?wxID_ANY), ok = wxTextCtrl:setValue(TTL_T, integer_to_list(DefTTL)), - GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), - GasP_T = wxTextCtrl:new(Frame, ?wxID_ANY), - ok = wxTextCtrl:setValue(GasP_T, integer_to_list(DefGasP)), Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), Gas_T = wxTextCtrl:new(Frame, ?wxID_ANY), ok = wxTextCtrl:setValue(Gas_T, integer_to_list(DefGas)), + GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), + GasP_T = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(GasP_T, integer_to_list(DefGasP)), Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), Amount_T = wxTextCtrl:new(Frame, ?wxID_ANY), ok = wxTextCtrl:setValue(Amount_T, integer_to_list(DefAmount)), _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, TTL_T, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_T, zxw:flags({wide, 5})), _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, Gas_T, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_T, zxw:flags({wide, 5})), _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, Amount_T, zxw:flags({wide, 5})), _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), Params = [{ "TTL", fun gte_0/1, TTL_T}, - {J("Gas Price"), fun gt_0/1, GasP_T}, {J("Gas") , fun gt_0/1, Gas_T}, + {J("Gas Price"), fun gt_0/1, GasP_T}, {J("TX Amount"), fun gte_0/1, Amount_T}], {ParamSz, Params}. @@ -289,13 +297,13 @@ engage3(State, ChainID, Params) -> engage4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> tell(info, "Args: ~p", [Args]), - {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, - case hz:contract_create_built(CallerID, Nonce, Gas, GP, Amount, TTL, Build, Args) of + {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, + case hz:contract_create_built(CallerID, Nonce, Amount, TTL, Gas, GP, Build, Args) of {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; engage4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> - {CallerID, Nonce, TTL, GP, Gas, Amount} = Params, + {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, AACI = maps:get(aaci, Build), case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of {ok, UnsignedTX} -> @@ -317,7 +325,7 @@ params(State = #s{kp = #w{wx = KeyPicker}}) -> params2(#s{params = Params}, PK, Nonce) -> case lists:foldl(fun extract/2, {ok, []}, Params) of - {ok, [TTL, GP, Gas, Amount]} -> {ok, {PK, Nonce, TTL, GP, Gas, Amount}}; + {ok, [Amount, GP, Gas, TTL]} -> {ok, {PK, Nonce, TTL, Gas, GP, Amount}}; Error -> Error end. @@ -344,9 +352,13 @@ deploy(State, ChainID, CallerID, CreateTX) -> deploy2(State, SignedTX) -> case hz:post_tx(SignedTX) of - {ok, Data} -> check_tx(State#s{tx_data = Data}); -% {ok, WTF} -> handle_troubling(State, {error, WTF}); - Error -> handle_troubling(State, Error) + {ok, Data} -> + case maps:is_key("reason", Data) of + false -> check_tx(State#s{tx_data = Data}); + true -> handle_troubling(State, {error, Data}) + end; + Error -> + handle_troubling(State, Error) end. @@ -358,7 +370,7 @@ do_call(State, ChainID, CallerID, UnsignedTX) -> do_call2(State, SignedTX) -> case hz:post_tx(SignedTX) of - {ok, Data} -> check_tx(State = #s{tx_data = Data}); + {ok, Data} -> check_tx(State#s{tx_data = Data}); Error -> handle_troubling(State, Error) end. @@ -391,14 +403,14 @@ check_tx(State = #s{tx_data = TXData}) -> update_info(State = #s{tx_info = TXInfo, out = #w{wx = Out}}) -> Formatted = io_lib:format("TXInfo: ~p~n", [TXInfo]), - ok = wxStaticText:setLabel(Out, Formatted), + ok = wxTextCtrl:setValue(Out, Formatted), State. copy(#s{tx_info = none}) -> ok; copy(#s{out = #w{wx = Out}}) -> - Output = wxStaticText:getLabel(Out), + Output = wxTextCtrl:getValue(Out), gd_lib:copy_to_clipboard(Output). diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index cd2d7e4..0b09b08 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -233,8 +233,8 @@ handle_cast({dryrun_result, ConID, CallInfo}, State) -> ok = do_dryrun_result(State, ConID, CallInfo), {noreply, State}; handle_cast({trouble, Info}, State) -> - ok = handle_troubling(State, Info), - {noreply, State}; + NewState = handle_troubling(State, Info), + {noreply, NewState}; handle_cast(Unexpected, State) -> ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]), {noreply, State}. @@ -287,8 +287,9 @@ handle_event(Event, State) -> {noreply, State}. -handle_troubling(#s{frame = Frame}, Info) -> - zxw:show_message(Frame, Info). +handle_troubling(State = #s{frame = Frame}, Info) -> + ok = zxw:show_message(Frame, Info), + State. code_change(_, State, _) -> @@ -374,20 +375,16 @@ add_code_page2(State = #s{j = J}, {file, File}) -> add_code_page(State, {file, File}, Code); Error -> Message = io_lib:format(J("Opening ~p failed with: ~p"), [File, Error]), - ok = handle_troubling(State, Message), - State + handle_troubling(State, Message) end; {error, Reason} -> Message = io_lib:format(J("Opening ~p failed with: ~p"), [File, Reason]), - ok = handle_troubling(State, Message), - State + handle_troubling(State, Message) end; add_code_page2(State, {hash, Address}) -> open_hash2(State, Address). add_code_page(State = #s{tabs = TopBook, code = {Codebook, Pages}}, Location, Code) -> - Color = wxSystemSettings:getColour(?wxSYS_COLOUR_WINDOW), - tell("Color: ~p", [Color]), Window = wxWindow:new(Codebook, ?wxID_ANY), PageSz = wxBoxSizer:new(?wxHORIZONTAL), @@ -612,8 +609,7 @@ open_hash2(State, Address) -> {ok, Source} -> open_hash3(State, Address, Source); Error -> - ok = handle_troubling(State, Error), - State + handle_troubling(State, Error) end. open_hash3(State, Address, Source) -> @@ -640,15 +636,11 @@ save(State = #s{prefs = Prefs, code = {Codebook, Pages}}) -> case filelib:ensure_dir(Path) of ok -> case file:write_file(Path, Source) of - ok -> - State; - Error -> - ok = handle_troubling(State, Error), - State + ok -> State; + Error -> handle_troubling(State, Error) end; Error -> - ok = handle_troubling(State, Error), - State + handle_troubling(State, Error) end; Page = #p{path = {hash, Hash}, code = Widget} -> DefDir = @@ -718,12 +710,10 @@ save_dialog(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pa NewCode = {Codebook, NewPages}, State#s{prefs = NewPrefs, code = NewCode}; Error -> - ok = handle_troubling(State, Error), - State + handle_troubling(State, Error) end; Error -> - ok = handle_troubling(State, Error), - State + handle_troubling(State, Error) end end; ?wxID_CANCEL -> @@ -773,8 +763,7 @@ load2(State, Address) -> {ok, Source} -> load3(State, Address, Source); Error -> - ok = handle_troubling(State, Error), - State + handle_troubling(State, Error) end. load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j = J}, -- 2.30.2 From 90d99e1eca37f9e063cc4ac3dfe2644909287d9b Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Sun, 3 May 2026 06:05:18 +0900 Subject: [PATCH 20/37] WIP --- src/gd_v_call.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 9d63721..568a30d 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -33,10 +33,11 @@ gasprice = #w{} :: #w{}, gas = #w{} :: #w{}, amount = #w{} :: #w{}, + status = none :: status(), action = #w{} :: #w{}, tx_data = none :: none | map(), - tx_hash = #w{} :: #w{}, - tx_info = none :: none | hz:transaction(), + tx_hash = #w{} :: #w{}, % wxTextCtrl, single-line + tx_info = none :: #w{}, % wxTextCtrl, multi-line out = #w{} :: #w{}, copy = #w{} :: #w{}}). @@ -45,6 +46,10 @@ -type fun_type() :: call | dryr | init. -type fun_def() :: {fun_name(), fun_type()}. -type param() :: {Label :: string(), Check :: fun(), #w{}}. +-type status() :: none + | {submitted, TX_Hash :: string()} + | {rejected, Reason :: string()} + | {included, TX_Info :: map()}. %%% Interface -- 2.30.2 From ae8c659c037a35c7f15bb5a1d29e72c59d2c794b Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 4 May 2026 23:58:02 +0900 Subject: [PATCH 21/37] WIP: Add gd_con:list_calls/0 and gd_v_call:tx_*/1 --- src/gd_con.erl | 14 ++++++++- src/gd_v_call.erl | 80 +++++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index a26c234..1e74652 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -16,7 +16,7 @@ refresh/0, nonce/1, spend/1, chain_id/0, grids/1, sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, - deploy/1, prompt_call/3, + deploy/1, prompt_call/3, list_calls/0, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). @@ -217,6 +217,18 @@ prompt_call(FunDef, ConID, Build) -> gen_server:cast(?MODULE, {prompt_call, FunDef, ConID, Build}). +-spec list_calls() -> Calls + when Calls :: [{Name, Process}], + Name :: term(), + Process :: wx:wx_object() | pid(). + +%% @doc +%% List any active contract call tasks. + +list_calls() -> + gen_server:call(?MODULE, list_calls). + + -spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok when Type :: {eddsa, ed25519}, Size :: 256, diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 568a30d..f89db0c 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -7,7 +7,7 @@ -behavior(wx_object). %-behavior(gd_v). -include_lib("wx/include/wx.hrl"). --export([to_front/1, result/2]). +-export([to_front/1, tx_hash/1, tx_data/1, tx_info/1]). -export([start_link/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). @@ -36,8 +36,9 @@ status = none :: status(), action = #w{} :: #w{}, tx_data = none :: none | map(), - tx_hash = #w{} :: #w{}, % wxTextCtrl, single-line - tx_info = none :: #w{}, % wxTextCtrl, multi-line + tx_info = none :: none | map(), + hash = #w{} :: #w{}, % wxTextCtrl, single-line + info = #w{} :: #w{}, % wxTextCtrl, multi-line out = #w{} :: #w{}, copy = #w{} :: #w{}}). @@ -47,9 +48,9 @@ -type fun_def() :: {fun_name(), fun_type()}. -type param() :: {Label :: string(), Check :: fun(), #w{}}. -type status() :: none - | {submitted, TX_Hash :: string()} - | {rejected, Reason :: string()} - | {included, TX_Info :: map()}. + | submitted + | rejected + | included. %%% Interface @@ -61,12 +62,28 @@ to_front(Win) -> wx_object:cast(Win, to_front). --spec result(Win, Outcome) -> ok - when Win :: wx:wx_object(), - Outcome :: term(). +-spec tx_hash(Win) -> Result + when Win :: pid() | wx:wx_object(), + Result :: none | string(). -result(Win, Outcome) -> - wx_object:cast(Win, {result, Outcome}). +tx_hash(Win) -> + wx_object:call(Win, tx_hash). + + +-spec tx_data(Win) -> Result + when Win :: pid() | wx:wx_object(), + Result :: none | map(). + +tx_hash(Win) -> + wx_object:call(Win, tx_data). + + +-spec tx_info(Win) -> Result + when Win :: pid() | wx:wx_object(), + Result :: none | map(). + +tx_hash(Win) -> + wx_object:call(Win, tx_info). @@ -146,7 +163,7 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, fundef = FunDef, con_id = ConID, build = Build, args = Args, kp = KP, params = Params, - action = Action, + action = Action, status = none, tx_data = TX_Data, tx_hash = TX_Hash, tx_info = TX_Info, out = Out, copy = Copy}, {Frame, State}. @@ -234,6 +251,12 @@ call_param_sizer(Frame, J) -> {ParamSz, Params}. +handle_call(tx_hash, _, State = #s{tx_hash = TXHash}) -> + {reply, TXHash, State}; +handle_call(tx_data, _, State = #s{tx_data = TXData}) -> + {reply, TXData, State}; +handle_call(tx_info, _, State = #s{tx_info = TXInfo}) -> + {reply, TXInfo, State}; handle_call(Unexpected, From, State) -> ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]), {noreply, State}. @@ -249,9 +272,13 @@ handle_info(Unexpected, State) -> {noreply, State}. +handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, + State = #s{action = #w{id = ID}, status = none}) -> + NewState = prep_call(State), + {noreply, NewState}; handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{action = #w{id = ID}}) -> - NewState = engage(State), + NewState = check_tx(State), {noreply, NewState}; handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{copy = #w{id = ID}}) -> @@ -280,34 +307,33 @@ handle_troubling(State = #s{frame = Frame}, Info) -> State. -engage(State) -> +prep_call(State) -> case gd_con:chain_id() of - {ok, ChainID} -> engage2(State, ChainID); + {ok, ChainID} -> prep_call2(State, ChainID); Error -> handle_troubling(State, Error) end. -engage2(State, ChainID) -> +prep_call2(State, ChainID) -> tell(info, "ChainID: ~p", [ChainID]), case params(State) of - {ok, Params} -> engage3(State, ChainID, Params); + {ok, Params} -> prep_call3(State, ChainID, Params); Error -> handle_troubling(State, Error) end. -engage3(State, ChainID, Params) -> +prep_call3(State, ChainID, Params) -> tell(info, "Params: ~p", [Params]), case args(State) of - {ok, Args} -> engage4(State, ChainID, Params, {sophia, Args}); + {ok, Args} -> prep_call4(State, ChainID, Params, {sophia, Args}); Error -> handle_troubling(State, Error) end. -engage4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> - tell(info, "Args: ~p", [Args]), +prep_call4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, case hz:contract_create_built(CallerID, Nonce, Amount, TTL, Gas, GP, Build, Args) of {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; -engage4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> +prep_call4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, AACI = maps:get(aaci, Build), case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of @@ -357,11 +383,11 @@ deploy(State, ChainID, CallerID, CreateTX) -> deploy2(State, SignedTX) -> case hz:post_tx(SignedTX) of - {ok, Data} -> - case maps:is_key("reason", Data) of - false -> check_tx(State#s{tx_data = Data}); - true -> handle_troubling(State, {error, Data}) - end; + {ok, Data = #{"tx_hash" := TXHash}} -> + ok = log(info, "Submitted transaction ~s", [TXHash]), + check_tx(State#s{tx_data = Data, status = submitted}); + {ok, #{"reason" := Reason}} -> + handle_troubling(State, {error, Reason}); Error -> handle_troubling(State, Error) end. -- 2.30.2 From 223552324f8e403acf15e776ee6ae2bbca6e6326 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 5 May 2026 00:27:59 +0900 Subject: [PATCH 22/37] WIP: Breaking reminder to add value amounts to total call cost --- src/gd_v_call.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index f89db0c..1f8b4e0 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -42,6 +42,7 @@ out = #w{} :: #w{}, copy = #w{} :: #w{}}). +show_the_amount_value() -> -type fun_name() :: string(). -type fun_type() :: call | dryr | init. -- 2.30.2 From 2a52516fd3c2ec27db7ca6ae417af8e6d8678393 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 5 May 2026 13:47:38 +0900 Subject: [PATCH 23/37] WIP --- src/gd_v_call.erl | 186 +++++++++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 77 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 1f8b4e0..206b5db 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -29,20 +29,15 @@ args = [] :: [#w{}], kp = #w{} :: #w{}, params = [] :: [param()], - ttl = #w{} :: #w{}, - gasprice = #w{} :: #w{}, - gas = #w{} :: #w{}, - amount = #w{} :: #w{}, + return = #w{} :: #w{}, % wxTextCtrl, single-line + copy = #w{} :: #w{}, status = none :: status(), action = #w{} :: #w{}, tx_data = none :: none | map(), tx_info = none :: none | map(), - hash = #w{} :: #w{}, % wxTextCtrl, single-line - info = #w{} :: #w{}, % wxTextCtrl, multi-line - out = #w{} :: #w{}, - copy = #w{} :: #w{}}). + hash = #w{} :: #w{}, % wxTextCtrl, single-line + info = #w{} :: #w{}}). % wxTextCtrl, multi-line -show_the_amount_value() -> -type fun_name() :: string(). -type fun_type() :: call | dryr | init. @@ -75,7 +70,7 @@ tx_hash(Win) -> when Win :: pid() | wx:wx_object(), Result :: none | map(). -tx_hash(Win) -> +tx_data(Win) -> wx_object:call(Win, tx_data). @@ -83,7 +78,7 @@ tx_hash(Win) -> when Win :: pid() | wx:wx_object(), Result :: none | map(). -tx_hash(Win) -> +tx_info(Win) -> wx_object:call(Win, tx_info). @@ -100,48 +95,40 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> J = gd_jt:j(Lang, Trans), {aaci, ConName, FunSpecs, _} = maps:get(aaci, Build), FunSpec = maps:get(FunName, FunSpecs), - {CallType, ActionLabel} = + {CallTypeLabel, ActionLabel} = case FunType of call -> {J("Contract Call"), J("Submit Call")}; dryr -> {J("Dry Run"), J("Submit Dry Run")}; init -> {J("Deploy"), J("Deploy")} end, Arity = integer_to_list(length(element(1, FunSpec))), - Title = [CallType, ": ", ConName, ".", FunName, "/", Arity], + Title = [CallTypeLabel, ": ", ConName, ".", FunName, "/", Arity], Wx = wx:new(), Frame = wxFrame:new(Wx, ?wxID_ANY, Title), MainSz = wxBoxSizer:new(?wxVERTICAL), KeySz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Signature Key")}]), - KeyPicker = wxChoice:new(Frame, ?wxID_ANY, [{choices, Keys}]), + KeyBox = wxStaticBoxSizer:getStaticBox(KeySz), + KeyPicker = wxChoice:new(KeyBox, ?wxID_ANY, [{choices, Keys}]), KP = #w{name = key_picker, id = wxChoice:getId(KeyPicker), wx = KeyPicker}, ZeroBasedSelected = Selected - 1, ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - {ArgSz, Args, HasArgs} = call_arg_sizer(Frame, J, FunSpec), + {ArgSz, Args, Return, Copy, HasArgs} = call_arg_sizer(Frame, J, FunType, FunSpec), {ParamSz, Params} = call_param_sizer(Frame, J), Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), TX_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Transaction Info")}]), TX_Sz_Box = wxStaticBoxSizer:getStaticBox(TX_Sz), - TxStyle = [{style, ?wxTE_READONLY}], - TX_Data = #w{wx = DataT} = gd_lib:mono_text(TX_Sz_Box, tx_data, "", TxStyle), - TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash, "", TxStyle), - TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_info, "", TxStyle), + Single = [{style, ?wxTE_READONLY}], + Multi = [{style, ?wxTE_MULTILINE bor ?wxTE_READONLY}], + TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash, "", Single), + TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_info, "", Multi), - Line = wxStaticLine:new(TX_Sz_Box, [{style, ?wxLI_HORIZONTAL}]), - OutStyle = [{style, ?wxTE_MULTILINE bor ?wxTE_READONLY}], - Out = #w{wx = OutTxt} = gd_lib:mono_text(TX_Sz_Box, out, "", OutStyle), - Copy = #w{wx = CopyBn} = gd_lib:button(TX_Sz_Box, J("Copy")), - - _ = wxStaticBoxSizer:add(TX_Sz, DataT, zxw:flags({base, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({base, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({base, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, Line, zxw:flags({base, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, OutTxt, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, CopyBn, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({base, 5})), ArgSzArgs = case HasArgs of @@ -152,7 +139,7 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> _ = wxSizer:add(MainSz, KeySz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ParamSz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ActionBn, zxw:flags({base, 5})), - _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({wide, 5})), + _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({base, 5})), _ = wxFrame:setSizer(Frame, MainSz), _ = wxFrame:setSize(Frame, {900, 900}), @@ -161,34 +148,37 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - fundef = FunDef, con_id = ConID, build = Build, - args = Args, kp = KP, params = Params, - action = Action, status = none, - tx_data = TX_Data, tx_hash = TX_Hash, tx_info = TX_Info, - out = Out, copy = Copy}, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + fundef = FunDef, con_id = ConID, build = Build, + args = Args, kp = KP, params = Params, + return = Return, copy = Copy, + action = Action, status = none, + hash = TX_Hash, info = TX_Info}, {Frame, State}. -call_arg_sizer(Frame, J, {CallArgs, ReturnType}) -> +call_arg_sizer(Frame, J, {CallArgs, FunType, ReturnType}) -> SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), - {CallSz, CallControls, HasArgs} = call_sizer(Frame, J, CallArgs), - ReturnSz = return_sizer(Frame, J, ReturnType), + SpecBox = wxStaticBoxSizer:getStaticBox(SpecSz), + {CallSz, CallControls, HasArgs} = call_sizer(SpecBox, J, CallArgs), + {ReturnSz, Return, Copy} = return_sizer(SpecBox, J, FunType, ReturnType), _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), - {SpecSz, CallControls, HasArgs}. + {SpecSz, CallControls, Return, Copy, HasArgs}. -call_sizer(Frame, J, []) -> - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), - Args = wxStaticText:new(Frame, ?wxID_ANY, ["[", J("No Args"), "]"]), +call_sizer(Parent, J, []) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Call Args")}]), + CallBox = wxStaticBoxSizer:getStaticBox(CallSz), + Args = wxStaticText:new(CallBox, ?wxID_ANY, ["[", J("No Args"), "]"]), _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), {CallSz, [], false}; -call_sizer(Frame, J, CallArgs) -> - ScrollWin = wxScrolledWindow:new(Frame), +call_sizer(Parent, J, CallArgs) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Call Args")}]), + CallBox = wxStaticBoxSizer:getStaticBox(CallSz), + ScrollWin = wxScrolledWindow:new(CallBox), ScrollSz = wxBoxSizer:new(?wxVERTICAL), ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), @@ -197,20 +187,30 @@ call_sizer(Frame, J, CallArgs) -> AddArg = fun({Name, Type}) -> L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), - C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), + C = #w{wx = T} = gd_lib:mono_text(ScrollWin, Name), _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), - #w{name = Name, id = wxTextCtrl:getId(C), wx = C} + _ = wxFlexGridSizer:add(GridSz, T, zxw:flags({wide, 5})), + C end, Controls = lists:map(AddArg, CallArgs), {CallSz, Controls, true}. -return_sizer(Frame, J, ReturnType) -> - ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Return Type")}]), +return_sizer(Parent, J, FunType, ReturnType) -> + TypeLabel = + case FunType =:= init of + false -> textify(ReturnType); + true -> J("Contract Address") + end, + ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Return Type")}]), ReturnSzBox = wxStaticBoxSizer:getStaticBox(ReturnSz), - Return = wxStaticText:new(ReturnSzBox, ?wxID_ANY, textify(ReturnType)), - _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), - ReturnSz. + ReturnLabel = wxStaticText:new(ReturnSzBox, ?wxID_ANY, TypeLabel), + Single = [{style, ?wxTE_READONLY}], + Return = #w{wx = ReturnTx} = gd_lib:mono_text(ReturnSzBox, return, "", Single), + Copy = #w{wx = CopyBn} = gd_lib:button(ReturnSzBox, J("Copy")), + _ = wxStaticBoxSizer:add(ReturnSz, ReturnLabel, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(ReturnSz, ReturnTx, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(ReturnSz, CopyBn, zxw:flags({wide, 5})), + {ReturnSz, Return, Copy}. call_param_sizer(Frame, J) -> @@ -220,20 +220,21 @@ call_param_sizer(Frame, J) -> DefGas = 5000000, DefAmount = 0, ParamSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("TX Parameters")}]), + ParamBox = wxStaticBoxSizer:getStaticBox(ParamSz), GridSz = wxFlexGridSizer:new(2, 4, 4), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), - TTL_T = wxTextCtrl:new(Frame, ?wxID_ANY), + TTL_L = wxStaticText:new(ParamBox, ?wxID_ANY, "TTL"), + TTL_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(TTL_T, integer_to_list(DefTTL)), - Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), - Gas_T = wxTextCtrl:new(Frame, ?wxID_ANY), + Gas_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("Gas")), + Gas_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(Gas_T, integer_to_list(DefGas)), - GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), - GasP_T = wxTextCtrl:new(Frame, ?wxID_ANY), + GasP_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("Gas Price")), + GasP_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(GasP_T, integer_to_list(DefGasP)), - Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), - Amount_T = wxTextCtrl:new(Frame, ?wxID_ANY), + Amount_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("TX Amount")), + Amount_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(Amount_T, integer_to_list(DefAmount)), _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, TTL_T, zxw:flags({wide, 5})), @@ -252,7 +253,8 @@ call_param_sizer(Frame, J) -> {ParamSz, Params}. -handle_call(tx_hash, _, State = #s{tx_hash = TXHash}) -> +handle_call(tx_hash, _, State) -> + TXHash = do_tx_hash(State), {reply, TXHash, State}; handle_call(tx_data, _, State = #s{tx_data = TXData}) -> {reply, TXData, State}; @@ -308,6 +310,12 @@ handle_troubling(State = #s{frame = Frame}, Info) -> State. +do_tx_hash(#s{tx_data = #{"tx_hash" := TXHash}}) -> + TXHash; +do_tx_hash(#s{tx_data = none}) -> + none. + + prep_call(State) -> case gd_con:chain_id() of {ok, ChainID} -> prep_call2(State, ChainID); @@ -315,14 +323,12 @@ prep_call(State) -> end. prep_call2(State, ChainID) -> - tell(info, "ChainID: ~p", [ChainID]), case params(State) of {ok, Params} -> prep_call3(State, ChainID, Params); Error -> handle_troubling(State, Error) end. prep_call3(State, ChainID, Params) -> - tell(info, "Params: ~p", [Params]), case args(State) of {ok, Args} -> prep_call4(State, ChainID, Params, {sophia, Args}); Error -> handle_troubling(State, Error) @@ -382,10 +388,13 @@ deploy(State, ChainID, CallerID, CreateTX) -> Error -> handle_troubling(State, Error) end. -deploy2(State, SignedTX) -> +deploy2(State = #s{hash = #w{wx = HashT}, action = #w{wx = ActionB}}, SignedTX) -> case hz:post_tx(SignedTX) of {ok, Data = #{"tx_hash" := TXHash}} -> + _ = wxButton:disable(ActionB), + ok = wxButton:setLabel(ActionB, J("Check Transaction Status")), ok = log(info, "Submitted transaction ~s", [TXHash]), + ok = wxTextCtrl:setValue(HashT, unicode:characters_to_list(TXHash)), check_tx(State#s{tx_data = Data, status = submitted}); {ok, #{"reason" := Reason}} -> handle_troubling(State, {error, Reason}); @@ -400,24 +409,47 @@ do_call(State, ChainID, CallerID, UnsignedTX) -> Error -> handle_troubling(State, Error) end. -do_call2(State, SignedTX) -> +do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) -> + _ = wxButton:disable(ActionB), + ok = wxButton:setLabel(ActionB, J("Check Transaction Status")), case hz:post_tx(SignedTX) of - {ok, Data} -> check_tx(State#s{tx_data = Data}); + {ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted}); Error -> handle_troubling(State, Error) end. -do_dry_run(State, ConID, TX) -> +do_dry_run(State = #s{action = #w{wx = ActionB}}, ConID, TX) -> + _ = wxButton:disable(ActionB), case hz:dry_run(TX) of {ok, Result} -> update_info(State#s{tx_info = Result}); Other -> handle_troubling(State, {error, ConID, Other}) end. - -check_tx(State = #s{tx_data = #{"tx_hash" := TXHash} = TXData, tx_info = none}) -> - ok = tell("TXData: ~p", [TXData]), +check_tx(State = #s{fundef = {_, init}, + tx_data = #{"tx_hash" := TXHash}, + tx_info = none, + return = #w{wx = ReturnT}, + status = submitted, + action = #w{wx = ActionB}, + info = #w{wx = InfoT}}) -> case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> + ok = wxTextCtrl:setValue(ReturnT, ConID), + ok = gd_v_devman:open_contract(ConID), + FormattedInfo = io_lib:fomat("~tw", [Info]), + ok = wxTextCtrl:setValue(InfoT, FormattedInfo), + +check_tx(State = #s{tx_data = #{"tx_hash" := TXHash}, + tx_info = none, + status = submitted, + action = #w{wx = ActionB}, + info = #w{wx = InfoT}}) -> + case hz:tx_info(TXHash) of + {ok, Info = #{"call_info" := #{"return_type" := "ok", + "contract_id" := ConID, + "return_value" := Value}}} -> + FormattedInfo = io_lib:fomat("~tw", [Info]), + ok = wxTextCtrl:setValue(InfoT, FormattedInfo), ok = gd_v_devman:open_contract(ConID), update_info(State#s{tx_info = Info}); {error, "Tx not mined"} -> @@ -433,16 +465,16 @@ check_tx(State = #s{tx_data = TXData}) -> State. -update_info(State = #s{tx_info = TXInfo, out = #w{wx = Out}}) -> +update_info(State = #s{tx_info = TXInfo, return = #w{wx = Return}}) -> Formatted = io_lib:format("TXInfo: ~p~n", [TXInfo]), - ok = wxTextCtrl:setValue(Out, Formatted), + ok = wxTextCtrl:setValue(Return, Formatted), State. copy(#s{tx_info = none}) -> ok; -copy(#s{out = #w{wx = Out}}) -> - Output = wxTextCtrl:getValue(Out), +copy(#s{return = #w{wx = Return}}) -> + Output = wxTextCtrl:getValue(Return), gd_lib:copy_to_clipboard(Output). -- 2.30.2 From 8b390f8d8269e60e7bf8d0bc8f31d1722a36449c Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Tue, 5 May 2026 22:11:14 +0900 Subject: [PATCH 24/37] WIP --- src/gd_v_call.erl | 111 ++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 206b5db..08e5a16 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -29,7 +29,7 @@ args = [] :: [#w{}], kp = #w{} :: #w{}, params = [] :: [param()], - return = #w{} :: #w{}, % wxTextCtrl, single-line + return = #w{} :: #w{}, % wxTextCtrl, single-line copy = #w{} :: #w{}, status = none :: status(), action = #w{} :: #w{}, @@ -40,8 +40,8 @@ -type fun_name() :: string(). --type fun_type() :: call | dryr | init. --type fun_def() :: {fun_name(), fun_type()}. +-type fun_ilk() :: call | dryr | init. +-type fun_def() :: {fun_name(), fun_ilk()}. -type param() :: {Label :: string(), Check :: fun(), #w{}}. -type status() :: none | submitted @@ -89,14 +89,14 @@ start_link(Args) -> wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). -init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> +init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) -> Lang = maps:get(lang, Prefs, en), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), {aaci, ConName, FunSpecs, _} = maps:get(aaci, Build), FunSpec = maps:get(FunName, FunSpecs), {CallTypeLabel, ActionLabel} = - case FunType of + case FunIlk of call -> {J("Contract Call"), J("Submit Call")}; dryr -> {J("Dry Run"), J("Submit Dry Run")}; init -> {J("Deploy"), J("Deploy")} @@ -115,7 +115,7 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), - {ArgSz, Args, Return, Copy, HasArgs} = call_arg_sizer(Frame, J, FunType, FunSpec), + {ArgSz, Args, Return, Copy, HasArgs} = call_arg_sizer(Frame, J, FunIlk, FunSpec), {ParamSz, Params} = call_param_sizer(Frame, J), Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), @@ -157,11 +157,11 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> {Frame, State}. -call_arg_sizer(Frame, J, {CallArgs, FunType, ReturnType}) -> +call_arg_sizer(Frame, J, FunIlk, {CallArgs, ReturnType}) -> SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), SpecBox = wxStaticBoxSizer:getStaticBox(SpecSz), {CallSz, CallControls, HasArgs} = call_sizer(SpecBox, J, CallArgs), - {ReturnSz, Return, Copy} = return_sizer(SpecBox, J, FunType, ReturnType), + {ReturnSz, Return, Copy} = return_sizer(SpecBox, J, FunIlk, ReturnType), _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), {SpecSz, CallControls, Return, Copy, HasArgs}. @@ -195,21 +195,22 @@ call_sizer(Parent, J, CallArgs) -> Controls = lists:map(AddArg, CallArgs), {CallSz, Controls, true}. -return_sizer(Parent, J, FunType, ReturnType) -> - TypeLabel = - case FunType =:= init of +return_sizer(Parent, J, FunIlk, ReturnType) -> + IlkLabel = + case FunIlk =:= init of false -> textify(ReturnType); true -> J("Contract Address") end, ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Return Type")}]), ReturnSzBox = wxStaticBoxSizer:getStaticBox(ReturnSz), - ReturnLabel = wxStaticText:new(ReturnSzBox, ?wxID_ANY, TypeLabel), + ReturnLabel = wxStaticText:new(ReturnSzBox, ?wxID_ANY, IlkLabel), Single = [{style, ?wxTE_READONLY}], Return = #w{wx = ReturnTx} = gd_lib:mono_text(ReturnSzBox, return, "", Single), - Copy = #w{wx = CopyBn} = gd_lib:button(ReturnSzBox, J("Copy")), + Copy = #w{wx = CopyB} = gd_lib:button(ReturnSzBox, J("Copy")), + _ = wxButton:disable(CopyB), _ = wxStaticBoxSizer:add(ReturnSz, ReturnLabel, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(ReturnSz, ReturnTx, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(ReturnSz, CopyBn, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(ReturnSz, ReturnTx, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(ReturnSz, CopyB, zxw:flags({wide, 5})), {ReturnSz, Return, Copy}. @@ -253,6 +254,9 @@ call_param_sizer(Frame, J) -> {ParamSz, Params}. + +%%% Spine + handle_call(tx_hash, _, State) -> TXHash = do_tx_hash(State), {reply, TXHash, State}; @@ -270,6 +274,8 @@ handle_cast(Unexpected, State) -> {noreply, State}. +handle_info(retire, State) -> + retire(State); handle_info(Unexpected, State) -> ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), {noreply, State}. @@ -287,9 +293,8 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{copy = #w{id = ID}}) -> ok = copy(State), {noreply, State}; -handle_event(#wx{event = #wxClose{}}, State = #s{frame = Frame}) -> - ok = wxWindow:destroy(Frame), - {noreply, State}; +handle_event(#wx{event = #wxClose{}}, State) -> + retire(State); handle_event(Event, State) -> ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. @@ -299,11 +304,19 @@ code_change(_, State, _) -> {ok, State}. +retire(State = #s{frame = Frame}) -> + ok = wxWindow:destroy(Frame), + {noreply, State}. + + terminate(Reason, State) -> ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), wx:destroy(). + +%%% Handlers + handle_troubling(State = #s{frame = Frame}, Info) -> ok = wxFrame:raise(Frame), ok = zxw:show_message(Frame, Info), @@ -340,12 +353,12 @@ prep_call4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; -prep_call4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> +prep_call4(State = #s{fundef = {Name, Ilk}, con_id = ConID, build = Build}, ChainID, Params, Args) -> {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, AACI = maps:get(aaci, Build), case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of {ok, UnsignedTX} -> - case Type of + case Ilk of call -> do_call(State, ChainID, CallerID, UnsignedTX); dryr -> do_dry_run(State, ConID, UnsignedTX) end; @@ -388,7 +401,7 @@ deploy(State, ChainID, CallerID, CreateTX) -> Error -> handle_troubling(State, Error) end. -deploy2(State = #s{hash = #w{wx = HashT}, action = #w{wx = ActionB}}, SignedTX) -> +deploy2(State = #s{j = J, hash = #w{wx = HashT}, action = #w{wx = ActionB}}, SignedTX) -> case hz:post_tx(SignedTX) of {ok, Data = #{"tx_hash" := TXHash}} -> _ = wxButton:disable(ActionB), @@ -411,7 +424,6 @@ do_call(State, ChainID, CallerID, UnsignedTX) -> do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) -> _ = wxButton:disable(ActionB), - ok = wxButton:setLabel(ActionB, J("Check Transaction Status")), case hz:post_tx(SignedTX) of {ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted}); Error -> handle_troubling(State, Error) @@ -425,41 +437,66 @@ do_dry_run(State = #s{action = #w{wx = ActionB}}, ConID, TX) -> Other -> handle_troubling(State, {error, ConID, Other}) end. -check_tx(State = #s{fundef = {_, init}, +check_tx(State = #s{frame = Frame, + j = J, + fundef = {_, init}, tx_data = #{"tx_hash" := TXHash}, tx_info = none, - return = #w{wx = ReturnT}, status = submitted, action = #w{wx = ActionB}, info = #w{wx = InfoT}}) -> case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> - ok = wxTextCtrl:setValue(ReturnT, ConID), - ok = gd_v_devman:open_contract(ConID), - FormattedInfo = io_lib:fomat("~tw", [Info]), - ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - -check_tx(State = #s{tx_data = #{"tx_hash" := TXHash}, + ok = tell(info, "Contract deployed: ~p", [Info]), + ok = gd_con:open_contract(ConID), + ok = wxWindow:destroy(Frame), + exit(0); + Other -> + FormattedJunk = io_lib:format("~tp", [Other]), + ok = wxTextCtrl:setValue(InfoT, FormattedJunk), + ok = wxButton:setLabel(ActionB, J("Deploy")), + _ = wxButton:enable(ActionB), + State#s{status = none} + end; +check_tx(State = #s{j = J, + con_id = ConID, + tx_data = #{"tx_hash" := TXHash}, tx_info = none, status = submitted, + return = #w{wx = ReturnT}, + copy = #w{wx = CopyB}, action = #w{wx = ActionB}, info = #w{wx = InfoT}}) -> case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID, "return_value" := Value}}} -> - FormattedInfo = io_lib:fomat("~tw", [Info]), + FormattedInfo = io_lib:fomat("~tp", [Info]), + _ = wxButton:enable(CopyB), + _ = wxButton:disable(ActionB), + ok = wxTextCtrl:setValue(ReturnT, Value), ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_v_devman:open_contract(ConID), - update_info(State#s{tx_info = Info}); - {error, "Tx not mined"} -> - handle_troubling(State, {error, not_mined}); + ok = gd_con:show_call_result(ConID, Info), + update_info(State#s{status = included, tx_info = Info}); {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> - handle_troubling(State, {error, Reason}); + _ = wxButton:enable(CopyB), + _ = wxButton:disable(ActionB), + FormattedInfo = io_lib:format("~tp", [Reason]), + ok = wxTextCtrl:setValue(ReturnT, FormattedInfo), % FIXME + ok = wxTextCtrl:setValue(InfoT, FormattedInfo), + ok = gd_con:show_call_result(ConID, Reason), + State#s{status = rejected, tx_info = Reason}; + {error, "Tx not mined"} -> + ok = wxTextCtrl:setValue(InfoT, J("Transaction not yet mined.")), + ok = wxButton:setLabel(ActionB, J("Check Transaction Status")), + _ = wxButton:enable(ActionB), + State; Error -> handle_troubling(State, Error) end; -check_tx(State = #s{tx_data = TXData}) -> +check_tx(State = #s{tx_data = TXData, + action = #w{wx = ActionB}}) -> + _ = wxButton:disable(ActionB), tell(info, "TXData: ~p", [TXData]), ok = tell("Nothing to check"), State. -- 2.30.2 From b071467faaded874bed82fe06204bb103f6fe56f Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 6 May 2026 12:46:26 +0900 Subject: [PATCH 25/37] Make Contract Calls Great Again --- src/gd_con.erl | 44 +++++++++++++++++++++- src/gd_v_call.erl | 92 +++++++++++++++++++++++++++++++-------------- src/gd_v_devman.erl | 33 ++-------------- 3 files changed, 110 insertions(+), 59 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index 1e74652..8745305 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -16,7 +16,7 @@ refresh/0, nonce/1, spend/1, chain_id/0, grids/1, sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, - deploy/1, prompt_call/3, list_calls/0, + deploy/1, prompt_call/3, list_calls/0, open_contract/1, show_call/2, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). @@ -210,7 +210,7 @@ deploy(Build) -> when FunDef :: {FunName, FunType}, FunName :: string(), FunType :: call | dryr | init, - ConID :: none | binary(), + ConID :: none | string(), Build :: map(). % Fixme prompt_call(FunDef, ConID, Build) -> @@ -229,6 +229,28 @@ list_calls() -> gen_server:call(?MODULE, list_calls). +-spec open_contract(ConID) -> ok + when ConID :: string(). +%% @doc +%% Ask the controller to tell the devman interface to open a deployed contract. +%% The controller will start the devman if it isn't already on. + +open_contract(ConID) -> + gen_server:cast(?MODULE, {open_contract, ConID}). + + +-spec show_call(ConID, Info) -> ok + when ConID :: string(), + Info :: map(). +%% @doc +%% Ask the controller to tell the devman interface to dislpay the result of a call +%% to the indicated contract. Opens the contract in question if it isn't alread open. +%% Starts the devman if it isn't already running. + +show_call(ConID, Info) -> + gen_server:cast(?MODULE, {show_call, ConID, Info}). + + -spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok when Type :: {eddsa, ed25519}, Size :: 256, @@ -499,6 +521,12 @@ handle_cast({rename_key, ID, NewName}, State) -> handle_cast({drop_key, ID}, State) -> NewState = do_drop_key(ID, State), {noreply, NewState}; +handle_cast({open_contract, ConID}, State) -> + NewState = do_open_contract(ConID, State), + {noreply, NewState}; +handle_cast({show_call, ConID, Info}, State) -> + NewState = do_show_call(ConID, Info, State), + {noreply, NewState}; handle_cast({add_node, New}, State) -> NewState = do_add_node(New, State), {noreply, NewState}; @@ -991,6 +1019,18 @@ do_drop_key(ID, State = #s{wallet = W, wallets = Wallets, pass = Pass}) -> State#s{wallet = NewWallet}. +do_open_contract(ConID, State) -> + NewState = do_show_ui(gd_v_devman, State), + ok = gd_v_devman:open_contract(ConID), + NewState. + + +do_show_call(ConID, Info, State) -> + NewState = do_show_ui(gd_v_devman, State), + ok = gd_v_devman:call_result(ConID, Info), + NewState. + + do_open_wallet(Path, Phrase, State = #s{timer = Timer}) -> Pass = pass(Phrase), case read(Path, Pass) of diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 08e5a16..e131c74 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -25,6 +25,7 @@ prefs = #{} :: map(), con_id = <<"">> :: binary(), fundef = none :: none | fun_def(), + funret = none :: none | term(), % FIXME build = none :: none | map(), args = [] :: [#w{}], kp = #w{} :: #w{}, @@ -94,14 +95,14 @@ init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) -> Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), {aaci, ConName, FunSpecs, _} = maps:get(aaci, Build), - FunSpec = maps:get(FunName, FunSpecs), + FunSpec = {FunArgs, FunReturn} = maps:get(FunName, FunSpecs), {CallTypeLabel, ActionLabel} = case FunIlk of call -> {J("Contract Call"), J("Submit Call")}; dryr -> {J("Dry Run"), J("Submit Dry Run")}; init -> {J("Deploy"), J("Deploy")} end, - Arity = integer_to_list(length(element(1, FunSpec))), + Arity = integer_to_list(length(FunArgs)), Title = [CallTypeLabel, ": ", ConName, ".", FunName, "/", Arity], Wx = wx:new(), Frame = wxFrame:new(Wx, ?wxID_ANY, Title), @@ -127,19 +128,19 @@ init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) -> TX_Hash = #w{wx = HashT} = gd_lib:mono_text(TX_Sz_Box, tx_hash, "", Single), TX_Info = #w{wx = InfoT} = gd_lib:mono_text(TX_Sz_Box, tx_info, "", Multi), - _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({base, 5})), - _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, HashT, zxw:flags({base, 5})), + _ = wxStaticBoxSizer:add(TX_Sz, InfoT, zxw:flags({wide, 5})), ArgSzArgs = case HasArgs of - true -> {wide, 5}; - false -> {base, 5} + true -> [{proportion, 2}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]; + false -> zxw:flags({base, 5}) end, - _ = wxSizer:add(MainSz, ArgSz, zxw:flags(ArgSzArgs)), + _ = wxSizer:add(MainSz, ArgSz, ArgSzArgs), _ = wxSizer:add(MainSz, KeySz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ParamSz, zxw:flags({base, 5})), _ = wxSizer:add(MainSz, ActionBn, zxw:flags({base, 5})), - _ = wxSizer:add(MainSz, TX_Sz, zxw:flags({base, 5})), + _ = wxSizer:add(MainSz, TX_Sz, [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), _ = wxFrame:setSizer(Frame, MainSz), _ = wxFrame:setSize(Frame, {900, 900}), @@ -148,9 +149,9 @@ init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) -> ok = wxFrame:connect(Frame, command_button_clicked), true = wxFrame:show(Frame), State = - #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, - fundef = FunDef, con_id = ConID, build = Build, - args = Args, kp = KP, params = Params, + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + fundef = FunDef, funret = FunReturn, con_id = ConID, build = Build, + args = Args, kp = KP, params = Params, return = Return, copy = Copy, action = Action, status = none, hash = TX_Hash, info = TX_Info}, @@ -306,7 +307,7 @@ code_change(_, State, _) -> retire(State = #s{frame = Frame}) -> ok = wxWindow:destroy(Frame), - {noreply, State}. + {stop, normal, State}. terminate(Reason, State) -> @@ -433,10 +434,44 @@ do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) -> do_dry_run(State = #s{action = #w{wx = ActionB}}, ConID, TX) -> _ = wxButton:disable(ActionB), case hz:dry_run(TX) of - {ok, Result} -> update_info(State#s{tx_info = Result}); + {ok, Result} -> dry_run2(State#s{tx_info = Result}); Other -> handle_troubling(State, {error, ConID, Other}) end. + +dry_run2(State = #s{funret = ReturnType, + return = #w{wx = ReturnT}, + copy = #w{wx = CopyB}, + tx_data = TXData, + tx_info = TXInfo, + hash = #w{wx = HashT}, + info = #w{wx = InfoT}}) -> + ReturnV = + case TXInfo of + #{"results" := + [#{"call_obj" := + #{"return_type" := "revert", + "return_value" := ReturnCB}, + "result" := "ok","type" := "contract_call"}]} -> + io_lib:format("Revert: ~ts", [hz:decode_bytearray(ReturnCB, sophia)]); + #{"results" := + [#{"call_obj" := + #{"return_type" := "ok", + "return_value" := ReturnCB}, + "result" := "ok","type" := "contract_call"}]} -> + hz:decode_bytearray(ReturnCB, {sophia, ReturnType}); + Other -> + io_lib:format("???: ~tp", [Other]) + end, + _ = wxButton:enable(CopyB), + FormattedHash = io_lib:format("~tp", [TXData]), + FormattedInfo = io_lib:format("~tp", [TXInfo]), + ok = wxTextCtrl:setValue(ReturnT, ReturnV), + ok = wxTextCtrl:setValue(HashT, FormattedHash), + ok = wxTextCtrl:setValue(InfoT, FormattedInfo), + State. + + check_tx(State = #s{frame = Frame, j = J, fundef = {_, init}, @@ -448,15 +483,22 @@ check_tx(State = #s{frame = Frame, case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> ok = tell(info, "Contract deployed: ~p", [Info]), + _ = wxButton:disable(ActionB), ok = gd_con:open_contract(ConID), ok = wxWindow:destroy(Frame), - exit(0); + self() ! retire, + State; + {error, "Tx not mined"} -> + ok = wxTextCtrl:setValue(InfoT, J("[Transaction not yet mined.]")), + ok = wxButton:setLabel(ActionB, J("Check Deployment Status")), + _ = wxButton:enable(ActionB), + State; Other -> FormattedJunk = io_lib:format("~tp", [Other]), ok = wxTextCtrl:setValue(InfoT, FormattedJunk), - ok = wxButton:setLabel(ActionB, J("Deploy")), + ok = wxButton:setLabel(ActionB, J("Check Depoyment Status")), _ = wxButton:enable(ActionB), - State#s{status = none} + State end; check_tx(State = #s{j = J, con_id = ConID, @@ -476,18 +518,18 @@ check_tx(State = #s{j = J, _ = wxButton:disable(ActionB), ok = wxTextCtrl:setValue(ReturnT, Value), ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call_result(ConID, Info), - update_info(State#s{status = included, tx_info = Info}); + ok = gd_con:show_call(ConID, Info), + State#s{status = included, tx_info = Info}; {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> _ = wxButton:enable(CopyB), _ = wxButton:disable(ActionB), FormattedInfo = io_lib:format("~tp", [Reason]), ok = wxTextCtrl:setValue(ReturnT, FormattedInfo), % FIXME ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call_result(ConID, Reason), + ok = gd_con:show_call(ConID, Reason), State#s{status = rejected, tx_info = Reason}; {error, "Tx not mined"} -> - ok = wxTextCtrl:setValue(InfoT, J("Transaction not yet mined.")), + ok = wxTextCtrl:setValue(InfoT, J("[Transaction not yet mined.]")), ok = wxButton:setLabel(ActionB, J("Check Transaction Status")), _ = wxButton:enable(ActionB), State; @@ -502,16 +544,10 @@ check_tx(State = #s{tx_data = TXData, State. -update_info(State = #s{tx_info = TXInfo, return = #w{wx = Return}}) -> - Formatted = io_lib:format("TXInfo: ~p~n", [TXInfo]), - ok = wxTextCtrl:setValue(Return, Formatted), - State. - - copy(#s{tx_info = none}) -> ok; -copy(#s{return = #w{wx = Return}}) -> - Output = wxTextCtrl:getValue(Return), +copy(#s{return = #w{wx = ReturnT}}) -> + Output = wxTextCtrl:getValue(ReturnT), gd_lib:copy_to_clipboard(Output). diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 0b09b08..4bc5a5a 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -559,41 +559,16 @@ open_file(State = #s{frame = Frame, j = J, prefs = Prefs}) -> open_hash(State = #s{frame = Frame, j = J}) -> - Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Retrieve Contract Source")), - Sizer = wxBoxSizer:new(?wxVERTICAL), - AddressSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Address Hash")}]), - AddressTx = wxTextCtrl:new(Dialog, ?wxID_ANY), - _ = wxSizer:add(AddressSz, AddressTx, zxw:flags(wide)), - ButtSz = wxBoxSizer:new(?wxHORIZONTAL), - Affirm = wxButton:new(Dialog, ?wxID_OK), - Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), - _ = wxSizer:add(Sizer, AddressSz, zxw:flags(wide)), - _ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)), - ok = wxDialog:setSizer(Dialog, Sizer), - ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, {500, 200}), - ok = wxDialog:center(Dialog), - ok = wxTextCtrl:setFocus(AddressTx), - Choice = - case wxDialog:showModal(Dialog) of - ?wxID_OK -> - case wxTextCtrl:getValue(AddressTx) of - "" -> cancel; - A -> {ok, A} - end; - ?wxID_CANCEL -> - cancel - end, - ok = wxDialog:destroy(Dialog), - case Choice of + Title = J("Retrieve Contract Source"), + Label = J("Address Hash"), + case zxw_modal_text:show(Frame, Title, [{label, Label}]) of {ok, Address = "ct_" ++ _} -> open_hash2(State, Address); {ok, Address = "th_" ++ _} -> get_contract_from_tx(State, Address); {ok, Turd} -> handle_troubling(State, {bad_address, Turd}); cancel -> State end. + get_contract_from_tx(State, Address) -> case hz:tx_info(Address) of {ok, #{"call_info" := #{"contract_id" := Contract}}} -> -- 2.30.2 From 41bd9eeacd7137e0636f34272256a2acefa74e73 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 6 May 2026 13:10:38 +0900 Subject: [PATCH 26/37] Ajust spacing --- src/gd_v_devman.erl | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 4bc5a5a..4645e41 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -759,11 +759,11 @@ load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j ConsSz = wxStaticBoxSizer:new(?wxVERTICAL, Window, [{label, J("Console")}]), ConsTxStyle = {style, ?wxTE_MULTILINE bor ?wxTE_READONLY}, ConsTx = wxTextCtrl:new(Window, ?wxID_ANY, [ConsTxStyle]), - _ = wxSizer:add(ConsSz, ConsTx, zxw:flags(wide)), - _ = wxSizer:add(ProgSz, CodeSz, [{proportion, 3}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(ProgSz, ScrollWin, [{proportion, 1}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(PageSz, ProgSz, [{proportion, 3}, {flag, ?wxEXPAND}]), - _ = wxSizer:add(PageSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(ConsSz, ConsTx, zxw:flags({wide, 5})), + _ = wxSizer:add(ProgSz, CodeSz, [{proportion, 3}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), + _ = wxSizer:add(ProgSz, ScrollWin, [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), + _ = wxSizer:add(PageSz, ProgSz, [{proportion, 3}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), + _ = wxSizer:add(PageSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, 5}]), {Out, IFaces, Build, NewButtons} = case compile(Source) of {ok, Output} -> @@ -798,15 +798,16 @@ fun_interfaces(ScrollWin, FunSz, Buttons, Funs, J) -> FLabel = wxStaticText:new(ScrollWin, ?wxID_ANY, FunName), CallBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Call")}]), DryRBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Dry Run")}]), - _ = wxBoxSizer:add(FS, FLabel, [{proportion, 1}, {flag, ?wxEXPAND}]), - _ = wxBoxSizer:add(FS, CallBn, [{proportion, 0}, {flag, ?wxEXPAND}]), - _ = wxBoxSizer:add(FS, DryRBn, [{proportion, 0}, {flag, ?wxEXPAND}]), + _ = wxBoxSizer:add(FS, FLabel, zxw:flags(wide)), + _ = wxBoxSizer:add(FS, CallBn, zxw:flags(base)), + _ = wxBoxSizer:add(FS, DryRBn, zxw:flags(base)), CallButton = #w{name = {Name, call}, id = wxButton:getId(CallBn), wx = CallBn}, DryRButton = #w{name = {Name, dryr}, id = wxButton:getId(DryRBn), wx = DryRBn}, - _ = wxSizer:add(FunSz, FS, zxw:flags(base)), + _ = wxSizer:add(FunSz, FS, zxw:flags({base, 5})), #f{name = Name, call = CallButton, dryrun = DryRButton, args = Args} end, - IFaces = maps:map(MakeIface, Funs), + Iterator = maps:iterator(Funs, ordered), + IFaces = maps:map(MakeIface, Iterator), NewButtons = maps:fold(fun map_iface_buttons/3, Buttons, IFaces), {NewButtons, IFaces}. -- 2.30.2 From b4dbf21c41db8a9fcaf5822d09c46249e1e182bd Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 6 May 2026 18:31:01 +0900 Subject: [PATCH 27/37] WIP: Fixing silly display cases --- src/gd_con.erl | 76 +++++++++++++++++++++++++++++++++++---------- src/gd_v_call.erl | 17 +++++----- src/gd_v_devman.erl | 14 +++++++-- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index 8745305..3fe11d4 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -16,7 +16,8 @@ refresh/0, nonce/1, spend/1, chain_id/0, grids/1, sign_mess/1, sign_binary/1, sign_tx/1, sign_call/3, - deploy/1, prompt_call/3, list_calls/0, open_contract/1, show_call/2, + deploy/1, prompt_call/3, list_calls/0, + open_contract/1, open_contract/2, show_call/2, show_call/3, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). -export([tic/1, update_balance/2]). @@ -26,7 +27,6 @@ -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). -include("$zx_include/zx_logger.hrl"). - -include("gd.hrl"). @@ -232,23 +232,48 @@ list_calls() -> -spec open_contract(ConID) -> ok when ConID :: string(). %% @doc +%% @equiv open_contract(ConID, true). + +open_contract(ConID) -> + open_contract(ConID, true). + + +-spec open_contract(ConID, DevmanToFront) -> ok + when ConID :: string(), + DevmanToFront :: boolean(). +%% @doc %% Ask the controller to tell the devman interface to open a deployed contract. %% The controller will start the devman if it isn't already on. -open_contract(ConID) -> - gen_server:cast(?MODULE, {open_contract, ConID}). +open_contract(ConID, DevmanToFront) when is_binary(ConID) -> + gen_server:cast(?MODULE, {open_contract, ConID, DevmanToFront}); +open_contract(ConID, DevmanToFront) when is_list(ConID) -> + open_contract(list_to_binary(ConID), DevmanToFront). -spec show_call(ConID, Info) -> ok when ConID :: string(), Info :: map(). %% @doc +%% @equiv show_call(ConID, Info, true). + +show_call(ConID, Info) -> + show_call(ConID, Info, true). + + +-spec show_call(ConID, Info, DevmanToFront) -> ok + when ConID :: string(), + Info :: map(), + DevmanToFront :: boolean(). +%% @doc %% Ask the controller to tell the devman interface to dislpay the result of a call %% to the indicated contract. Opens the contract in question if it isn't alread open. %% Starts the devman if it isn't already running. -show_call(ConID, Info) -> - gen_server:cast(?MODULE, {show_call, ConID, Info}). +show_call(ConID, Info, DevmanToFront) when is_binary(ConID) -> + gen_server:cast(?MODULE, {show_call, ConID, Info, DevmanToFront}); +show_call(ConID, Info, DevmanToFront) when is_list(ConID) -> + show_call(list_to_binary(ConID), Info, DevmanToFront). -spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok @@ -521,11 +546,11 @@ handle_cast({rename_key, ID, NewName}, State) -> handle_cast({drop_key, ID}, State) -> NewState = do_drop_key(ID, State), {noreply, NewState}; -handle_cast({open_contract, ConID}, State) -> - NewState = do_open_contract(ConID, State), +handle_cast({open_contract, ConID, ToFront}, State) -> + NewState = do_open_contract(ConID, ToFront, State), {noreply, NewState}; -handle_cast({show_call, ConID, Info}, State) -> - NewState = do_show_call(ConID, Info, State), +handle_cast({show_call, ConID, Info, ToFront}, State) -> + NewState = do_show_call(ConID, Info, ToFront, State), {noreply, NewState}; handle_cast({add_node, New}, State) -> NewState = do_add_node(New, State), @@ -594,11 +619,29 @@ terminate(Reason, _) -> %%% GUI doers +-spec do_show_ui(Name, State) -> NewState + when Name :: ui_name() | term(), + State :: state(), + NewState :: state(). -do_show_ui(Name, State = #s{tasks = Tasks, prefs = Prefs}) -> +do_show_ui(Name, State) -> + do_show_ui(Name, true, State). + + +-spec do_show_ui(Name, ToFront, State) -> NewState + when Name :: ui_name() | term(), + ToFront :: boolean(), + State :: state(), + NewState :: state(). + +do_show_ui(Name, ToFront, State = #s{tasks = Tasks, prefs = Prefs}) -> case lists:keyfind(Name, #ui.name, Tasks) of #ui{wx = Win} -> - ok = Name:to_front(Win), + ok = + case ToFront of + true -> Name:to_front(Win); + false -> ok + end, State; false -> TaskPrefs = maps:get(Name, Prefs, #{}), @@ -1019,14 +1062,15 @@ do_drop_key(ID, State = #s{wallet = W, wallets = Wallets, pass = Pass}) -> State#s{wallet = NewWallet}. -do_open_contract(ConID, State) -> - NewState = do_show_ui(gd_v_devman, State), +do_open_contract(ConID, ToFront, State) -> + NewState = do_show_ui(gd_v_devman, ToFront, State), ok = gd_v_devman:open_contract(ConID), NewState. -do_show_call(ConID, Info, State) -> - NewState = do_show_ui(gd_v_devman, State), +do_show_call(ConID, Info, ToFront, State) -> + NewState = do_show_ui(gd_v_devman, ToFront, State), + ok = gd_v_devman:open_contract(ConID), ok = gd_v_devman:call_result(ConID, Info), NewState. diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index e131c74..586ffec 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -501,6 +501,7 @@ check_tx(State = #s{frame = Frame, State end; check_tx(State = #s{j = J, + funret = ReturnType, con_id = ConID, tx_data = #{"tx_hash" := TXHash}, tx_info = none, @@ -512,21 +513,23 @@ check_tx(State = #s{j = J, case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID, - "return_value" := Value}}} -> - FormattedInfo = io_lib:fomat("~tp", [Info]), + "return_value" := ReturnCB}}} -> + FormattedInfo = io_lib:format("~tp", [Info]), _ = wxButton:enable(CopyB), _ = wxButton:disable(ActionB), - ok = wxTextCtrl:setValue(ReturnT, Value), + ReturnV = hz:decode_bytearray(ReturnCB, {sophia, ReturnType}), + ok = wxTextCtrl:setValue(ReturnT, ReturnV), ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call(ConID, Info), + ok = gd_con:show_call(ConID, Info, false), State#s{status = included, tx_info = Info}; - {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> + {ok, Reason = #{"call_info" := #{"return_type" := "revert", "return_value" := ReturnCB}}} -> _ = wxButton:enable(CopyB), _ = wxButton:disable(ActionB), + ReturnV = io_lib:format("Revert: ~ts", [hz:decode_bytearray(ReturnCB, sophia)]), + ok = wxTextCtrl:setValue(ReturnT, ReturnV), FormattedInfo = io_lib:format("~tp", [Reason]), - ok = wxTextCtrl:setValue(ReturnT, FormattedInfo), % FIXME ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call(ConID, Reason), + ok = gd_con:show_call(ConID, Reason, false), State#s{status = rejected, tx_info = Reason}; {error, "Tx not mined"} -> ok = wxTextCtrl:setValue(InfoT, J("[Transaction not yet mined.]")), diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 4645e41..d63b284 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -733,15 +733,23 @@ load_from_tx(State, Address) -> handle_troubling(State, Error) end. -load2(State, Address) -> +load2(State = #s{cons = {_, Pages}}, Address) when is_binary(Address) -> + case lists:keyfind(Address, #c.id, Pages) of + false -> load3(State, Address); + #c{} -> State + end; +load2(State, Address) when is_list(Address) -> + load2(State, list_to_binary(Address)). + +load3(State, Address) -> case hz:contract_source(Address) of {ok, Source} -> - load3(State, Address, Source); + load4(State, Address, Source); Error -> handle_troubling(State, Error) end. -load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j = J}, +load4(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j = J}, Address, Source) -> Window = wxWindow:new(Consbook, ?wxID_ANY), -- 2.30.2 From ca933a33db33e7e7d2f996ccc934fc4e95c2ba1d Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 12:46:00 +0900 Subject: [PATCH 28/37] WIP --- src/gd_v_call.erl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 586ffec..11d19a2 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -87,7 +87,7 @@ tx_info(Win) -> %%% Startup Functions start_link(Args) -> - wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). + wx_object:start_link(?MODULE, Args, []). init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) -> @@ -472,8 +472,7 @@ dry_run2(State = #s{funret = ReturnType, State. -check_tx(State = #s{frame = Frame, - j = J, +check_tx(State = #s{j = J, fundef = {_, init}, tx_data = #{"tx_hash" := TXHash}, tx_info = none, @@ -485,7 +484,6 @@ check_tx(State = #s{frame = Frame, ok = tell(info, "Contract deployed: ~p", [Info]), _ = wxButton:disable(ActionB), ok = gd_con:open_contract(ConID), - ok = wxWindow:destroy(Frame), self() ! retire, State; {error, "Tx not mined"} -> @@ -502,7 +500,6 @@ check_tx(State = #s{frame = Frame, end; check_tx(State = #s{j = J, funret = ReturnType, - con_id = ConID, tx_data = #{"tx_hash" := TXHash}, tx_info = none, status = submitted, @@ -512,7 +509,6 @@ check_tx(State = #s{j = J, info = #w{wx = InfoT}}) -> case hz:tx_info(TXHash) of {ok, Info = #{"call_info" := #{"return_type" := "ok", - "contract_id" := ConID, "return_value" := ReturnCB}}} -> FormattedInfo = io_lib:format("~tp", [Info]), _ = wxButton:enable(CopyB), @@ -520,7 +516,6 @@ check_tx(State = #s{j = J, ReturnV = hz:decode_bytearray(ReturnCB, {sophia, ReturnType}), ok = wxTextCtrl:setValue(ReturnT, ReturnV), ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call(ConID, Info, false), State#s{status = included, tx_info = Info}; {ok, Reason = #{"call_info" := #{"return_type" := "revert", "return_value" := ReturnCB}}} -> _ = wxButton:enable(CopyB), @@ -529,7 +524,6 @@ check_tx(State = #s{j = J, ok = wxTextCtrl:setValue(ReturnT, ReturnV), FormattedInfo = io_lib:format("~tp", [Reason]), ok = wxTextCtrl:setValue(InfoT, FormattedInfo), - ok = gd_con:show_call(ConID, Reason, false), State#s{status = rejected, tx_info = Reason}; {error, "Tx not mined"} -> ok = wxTextCtrl:setValue(InfoT, J("[Transaction not yet mined.]")), -- 2.30.2 From 1c59ed413a3ca9abda1e2145b2677254c7599862 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 16:28:23 +0900 Subject: [PATCH 29/37] Line numbers --- src/gd_sophia_editor.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index ee9a7a3..03b62ed 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -97,6 +97,8 @@ new(Parent) -> [{face, "Monospace"}]), SetMonospace = fun(Style) -> wxStyledTextCtrl:styleSetFont(STC, Style, Mono) end, ok = lists:foreach(SetMonospace, styles()), + ok = wxStyledTextCtrl:setMarginType(STC, 0, ?wxSTC_MARGIN_NUMBER), + ok = wxStyledTextCtrl:setMarginWidth(STC, 0, 40), ok = wxStyledTextCtrl:styleSetFont(STC, ?wxSTC_STYLE_DEFAULT, Mono), ok = set_colors(STC), STC. -- 2.30.2 From 5a745af71beb6847c8acc1d035b47631005dba90 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 16:46:04 +0900 Subject: [PATCH 30/37] Line number colors --- src/gd_sophia_editor.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index 03b62ed..e60946a 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -67,6 +67,8 @@ palette(light) -> ?STRING => ?red, ?NUMBER => ?magenta, ?OPERATOR => ?brown, + line_num => ?brown, + cursor => ?black, bg => ?high_white}; palette(dark) -> #{?DEFAULT => ?white, @@ -76,6 +78,8 @@ palette(dark) -> ?STRING => ?light_red, ?NUMBER => ?light_magenta, ?OPERATOR => ?yellow, + line_num => ?light_cyan, + cursor => ?white, bg => ?not_black}. color_mode() -> @@ -114,13 +118,15 @@ set_text(STC, Text) -> set_colors(STC) -> ok = wxStyledTextCtrl:styleClearAll(STC), - Palette = #{bg := BGC} = palette(color_mode()), + Palette = #{bg := BGC, cursor := CC, line_num := LNC} = palette(color_mode()), Colorize = fun(Style) -> Color = maps:get(Style, Palette), ok = wxStyledTextCtrl:styleSetForeground(STC, Style, Color), ok = wxStyledTextCtrl:styleSetBackground(STC, Style, BGC) end, + ok = wxStyledTextCtrl:setCaretForeground(STC, CC), + ok = wxStyledTextCtrl:styleSetForeground(STC, ?wxSTC_STYLE_LINENUMBER, LNC), ok = wxStyledTextCtrl:styleSetBackground(STC, ?wxSTC_STYLE_DEFAULT, BGC), lists:foreach(Colorize, styles()). -- 2.30.2 From 115ca656ba989292c11c0af683fb634723882bdb Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 17:04:43 +0900 Subject: [PATCH 31/37] Marginally better line numbers --- src/gd_sophia_editor.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index e60946a..453dfb9 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -78,7 +78,7 @@ palette(dark) -> ?STRING => ?light_red, ?NUMBER => ?light_magenta, ?OPERATOR => ?yellow, - line_num => ?light_cyan, + line_num => ?yellow, cursor => ?white, bg => ?not_black}. -- 2.30.2 From 0c9e9805f0002f6995ac51e9912d0e1c181c13ee Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 18:43:43 +0900 Subject: [PATCH 32/37] Fix highlighting --- src/gd_sophia_editor.erl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index 453dfb9..014098a 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -26,6 +26,7 @@ -define(H, 255). % High -define(M, 192). % Medium -define(L, 128). % Low +-define(D, 64). % Deep-Low -define(X, 32). % X-Low -define(Z, 0). % Zilch @@ -46,8 +47,9 @@ -define(brown, {?L, ?L, ?Z}). -define(magenta, {?L, ?Z, ?L}). -define(cyan, {?Z, ?L, ?L}). --define(not_black, {?X, ?X, ?X}). -define(grey, {?L, ?L, ?L}). +-define(dark_grey, {?D, ?D, ?D}). +-define(not_black, {?X, ?X, ?X}). -define(white, {?M, ?M, ?M}). styles() -> @@ -67,6 +69,7 @@ palette(light) -> ?STRING => ?red, ?NUMBER => ?magenta, ?OPERATOR => ?brown, + sel_back => ?grey, line_num => ?brown, cursor => ?black, bg => ?high_white}; @@ -78,6 +81,7 @@ palette(dark) -> ?STRING => ?light_red, ?NUMBER => ?light_magenta, ?OPERATOR => ?yellow, + sel_back => ?dark_grey, line_num => ?yellow, cursor => ?white, bg => ?not_black}. @@ -118,7 +122,8 @@ set_text(STC, Text) -> set_colors(STC) -> ok = wxStyledTextCtrl:styleClearAll(STC), - Palette = #{bg := BGC, cursor := CC, line_num := LNC} = palette(color_mode()), + Palette = palette(color_mode()), + #{bg := BGC, cursor := CC, line_num := LNC, sel_back := SFB} = Palette, Colorize = fun(Style) -> Color = maps:get(Style, Palette), @@ -126,6 +131,7 @@ set_colors(STC) -> ok = wxStyledTextCtrl:styleSetBackground(STC, Style, BGC) end, ok = wxStyledTextCtrl:setCaretForeground(STC, CC), + ok = wxStyledTextCtrl:setSelBackground(STC, true, SFB), ok = wxStyledTextCtrl:styleSetForeground(STC, ?wxSTC_STYLE_LINENUMBER, LNC), ok = wxStyledTextCtrl:styleSetBackground(STC, ?wxSTC_STYLE_DEFAULT, BGC), lists:foreach(Colorize, styles()). -- 2.30.2 From 6f9555a7c9f09d4655f2bb07c51daaeae6299b0c Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Thu, 7 May 2026 19:53:10 +0900 Subject: [PATCH 33/37] Handle invalid calls slightly better --- src/gd_v_call.erl | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 11d19a2..5b2a306 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -226,32 +226,32 @@ call_param_sizer(Frame, J) -> GridSz = wxFlexGridSizer:new(2, 4, 4), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - TTL_L = wxStaticText:new(ParamBox, ?wxID_ANY, "TTL"), - TTL_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), - ok = wxTextCtrl:setValue(TTL_T, integer_to_list(DefTTL)), + Amount_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("Amount")), + Amount_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), + ok = wxTextCtrl:setValue(Amount_T, integer_to_list(DefAmount)), Gas_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("Gas")), Gas_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(Gas_T, integer_to_list(DefGas)), GasP_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("Gas Price")), GasP_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), ok = wxTextCtrl:setValue(GasP_T, integer_to_list(DefGasP)), - Amount_L = wxStaticText:new(ParamBox, ?wxID_ANY, J("TX Amount")), - Amount_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), - ok = wxTextCtrl:setValue(Amount_T, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, TTL_T, zxw:flags({wide, 5})), + TTL_L = wxStaticText:new(ParamBox, ?wxID_ANY, "TTL"), + TTL_T = wxTextCtrl:new(ParamBox, ?wxID_ANY), + ok = wxTextCtrl:setValue(TTL_T, integer_to_list(DefTTL)), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_T, zxw:flags({wide, 5})), _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, Gas_T, zxw:flags({wide, 5})), _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), _ = wxFlexGridSizer:add(GridSz, GasP_T, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_T, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_T, zxw:flags({wide, 5})), _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), Params = - [{ "TTL", fun gte_0/1, TTL_T}, + [{J("TX Amount"), fun gte_0/1, Amount_T} , {J("Gas") , fun gt_0/1, Gas_T}, {J("Gas Price"), fun gt_0/1, GasP_T}, - {J("TX Amount"), fun gte_0/1, Amount_T}], + { "TTL", fun gte_0/1, TTL_T}], {ParamSz, Params}. @@ -349,13 +349,13 @@ prep_call3(State, ChainID, Params) -> end. prep_call4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params, Args) -> - {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, - case hz:contract_create_built(CallerID, Nonce, Amount, TTL, Gas, GP, Build, Args) of + {CallerID, Nonce, Gas, GP, Amount, TTL} = Params, + case hz:contract_create_built(CallerID, Nonce, Gas, GP, Amount, TTL, Build, Args) of {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); Error -> handle_troubling(State, Error) end; prep_call4(State = #s{fundef = {Name, Ilk}, con_id = ConID, build = Build}, ChainID, Params, Args) -> - {CallerID, Nonce, TTL, Gas, GP, Amount} = Params, + {CallerID, Nonce, Gas, GP, Amount, TTL} = Params, AACI = maps:get(aaci, Build), case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of {ok, UnsignedTX} -> @@ -377,7 +377,7 @@ params(State = #s{kp = #w{wx = KeyPicker}}) -> params2(#s{params = Params}, PK, Nonce) -> case lists:foldl(fun extract/2, {ok, []}, Params) of - {ok, [Amount, GP, Gas, TTL]} -> {ok, {PK, Nonce, TTL, Gas, GP, Amount}}; + {ok, [TTL, GP, Gas, Amount]} -> {ok, {PK, Nonce, Gas, GP, Amount, TTL}}; Error -> Error end. @@ -426,8 +426,9 @@ do_call(State, ChainID, CallerID, UnsignedTX) -> do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) -> _ = wxButton:disable(ActionB), case hz:post_tx(SignedTX) of - {ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted}); - Error -> handle_troubling(State, Error) + {ok, #{"reason" := Reason}} -> handle_troubling(State#s{status = rejected}, Reason); + {ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted}); + Error -> handle_troubling(State, Error) end. -- 2.30.2 From 28f4a20bc00a771952fa3e695ba9af274b3a17f4 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Sat, 9 May 2026 21:44:04 +0900 Subject: [PATCH 34/37] Adapt to possible hz outputs for contract source --- src/gd_v_devman.erl | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index d63b284..f3e625e 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -76,10 +76,12 @@ set_manifest(Entries) -> -spec open_contract(Address) -> ok - when Address :: string(). + when Address :: binary() | string(). -open_contract(Address) -> - wx_object:cast(?MODULE, {open_contract, Address}). +open_contract(Address) when is_binary(Address) -> + wx_object:cast(?MODULE, {open_contract, Address}); +open_contract(Address) when is_list(Address) -> + open_contract(list_to_binary(Address)). -spec write_console(ConID, Message) -> ok @@ -562,8 +564,8 @@ open_hash(State = #s{frame = Frame, j = J}) -> Title = J("Retrieve Contract Source"), Label = J("Address Hash"), case zxw_modal_text:show(Frame, Title, [{label, Label}]) of - {ok, Address = "ct_" ++ _} -> open_hash2(State, Address); - {ok, Address = "th_" ++ _} -> get_contract_from_tx(State, Address); + {ok, Address = "ct_" ++ _} -> open_hash2(State, list_to_binary(Address)); + {ok, Address = "th_" ++ _} -> get_contract_from_tx(State, list_to_binary(Address)); {ok, Turd} -> handle_troubling(State, {bad_address, Turd}); cancel -> State end. @@ -581,7 +583,11 @@ get_contract_from_tx(State, Address) -> open_hash2(State, Address) -> case hz:contract_source(Address) of + {project, [{Name, Source}]} -> + ok = tell("Retrieved ~p from ~p", [Name, Address]), + open_hash3(State, Address, Source); {ok, Source} -> + ok = tell("Retrieved uncompressed source of ~p", [Address]), open_hash3(State, Address, Source); Error -> handle_troubling(State, Error) @@ -590,9 +596,7 @@ open_hash2(State, Address) -> open_hash3(State, Address, Source) -> % TODO: Compile on load and verify the deployed hash for validity. case compile(Source) of - {ok, Build} -> - {aaci, _, FunDefs, _} = maps:get(aaci, Build), - ok = tell(info, "Compilation Succeeded!~n~tp~n~n~tp", [Build, FunDefs]), + {ok, _Build} -> add_code_page(State, {hash, Address}, Source); Other -> ok = tell(info, "Compilation Failed!~n~tp", [Other]), @@ -743,7 +747,11 @@ load2(State, Address) when is_list(Address) -> load3(State, Address) -> case hz:contract_source(Address) of + {project, [{Name, Source}]} -> + ok = tell("Retrieved ~p from ~p", [Name, Address]), + load4(State, Address, Source); {ok, Source} -> + ok = tell("Retrieved uncompressed source of ~p", [Address]), load4(State, Address, Source); Error -> handle_troubling(State, Error) @@ -777,7 +785,6 @@ load4(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j {ok, Output} -> {aaci, _, Funs, _} = maps:get(aaci, Output), Callable = maps:remove("init", Funs), - tell(info, "Callable: ~p", [Callable]), {NB, IFs} = fun_interfaces(ScrollWin, FunSz, Buttons, Callable, J), O = io_lib:format("Compilation Succeeded!~n~tp~n~nDone!~n", [Output]), {O, IFs, Output, NB}; -- 2.30.2 From e5db26ab4c3495270fefc0d117dab2c1d9e27593 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Sun, 10 May 2026 12:36:44 +0900 Subject: [PATCH 35/37] verup --- ebin/gajudesk.app | 2 +- src/gajudesk.erl | 2 +- src/gd_con.erl | 2 +- src/gd_grids.erl | 2 +- src/gd_gui.erl | 2 +- src/gd_jt.erl | 2 +- src/gd_lib.erl | 2 +- src/gd_m_spend.erl | 2 +- src/gd_m_wallet_importer.erl | 2 +- src/gd_sophia_editor.erl | 2 +- src/gd_sup.erl | 2 +- src/gd_v.erl | 2 +- src/gd_v_call.erl | 2 +- src/gd_v_devman.erl | 2 +- src/gd_v_netman.erl | 2 +- src/gd_v_wallman.erl | 2 +- zomp.meta | 4 ++-- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ebin/gajudesk.app b/ebin/gajudesk.app index 662b0c2..293be9a 100644 --- a/ebin/gajudesk.app +++ b/ebin/gajudesk.app @@ -3,7 +3,7 @@ {registered,[]}, {included_applications,[]}, {applications,[stdlib,kernel,sasl,ssl]}, - {vsn,"0.8.1"}, + {vsn,"0.9.0"}, {modules,[gajudesk,gd_con,gd_grids,gd_gui,gd_jt,gd_lib, gd_m_spend,gd_m_wallet_importer,gd_sophia_editor, gd_sup,gd_v,gd_v_devman,gd_v_netman,gd_v_wallman]}, diff --git a/src/gajudesk.erl b/src/gajudesk.erl index 28d0fcf..f2eb4a1 100644 --- a/src/gajudesk.erl +++ b/src/gajudesk.erl @@ -3,7 +3,7 @@ %%% @end -module(gajudesk). --vsn("0.8.1"). +-vsn("0.9.0"). -behavior(application). -author("Craig Everett "). -copyright("QPQ AG "). diff --git a/src/gd_con.erl b/src/gd_con.erl index 3fe11d4..f655c57 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -3,7 +3,7 @@ %%% @end -module(gd_con). --vsn("0.8.1"). +-vsn("0.9.0"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_grids.erl b/src/gd_grids.erl index 75d6091..ee4de93 100644 --- a/src/gd_grids.erl +++ b/src/gd_grids.erl @@ -37,7 +37,7 @@ %%% @end -module(gd_grids). --vsn("0.8.1"). +-vsn("0.9.0"). -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 f73dfd5..82d909a 100644 --- a/src/gd_gui.erl +++ b/src/gd_gui.erl @@ -3,7 +3,7 @@ %%% @end -module(gd_gui). --vsn("0.8.1"). +-vsn("0.9.0"). -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 b94583d..303fa68 100644 --- a/src/gd_jt.erl +++ b/src/gd_jt.erl @@ -15,7 +15,7 @@ %%% translation library is retained). -module(gd_jt). --vsn("0.8.1"). +-vsn("0.9.0"). -export([read_translations/1, j/2, oneshot_j/2]). diff --git a/src/gd_lib.erl b/src/gd_lib.erl index a8512eb..d7af461 100644 --- a/src/gd_lib.erl +++ b/src/gd_lib.erl @@ -3,7 +3,7 @@ %%% @end -module(gd_lib). --vsn("0.8.1"). +-vsn("0.9.0"). -include_lib("wx/include/wx.hrl"). -export([is_int/1, diff --git a/src/gd_m_spend.erl b/src/gd_m_spend.erl index 47d147e..fb31f22 100644 --- a/src/gd_m_spend.erl +++ b/src/gd_m_spend.erl @@ -3,7 +3,7 @@ %%% @end -module(gd_m_spend). --vsn("0.8.1"). +-vsn("0.9.0"). -author("Craig Everett "). -copyright("Craig Everett "). -license("GPL-3.0-or-later"). diff --git a/src/gd_m_wallet_importer.erl b/src/gd_m_wallet_importer.erl index 3510f4e..4b88cb6 100644 --- a/src/gd_m_wallet_importer.erl +++ b/src/gd_m_wallet_importer.erl @@ -5,7 +5,7 @@ %%% @end -module(gd_m_wallet_importer). --vsn("0.8.1"). +-vsn("0.9.0"). -author("Craig Everett "). -copyright("Craig Everett "). -license("GPL-3.0-or-later"). diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index 014098a..1c6c8f3 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -1,5 +1,5 @@ -module(gd_sophia_editor). --vsn("0.8.1"). +-vsn("0.9.0"). -export([new/1, update/1, update/2, get_text/1, set_text/2]). diff --git a/src/gd_sup.erl b/src/gd_sup.erl index 0ca4d64..5bac2bd 100644 --- a/src/gd_sup.erl +++ b/src/gd_sup.erl @@ -12,7 +12,7 @@ %%% @end -module(gd_sup). --vsn("0.8.1"). +-vsn("0.9.0"). -behaviour(supervisor). -author("Craig Everett "). -copyright("QPQ AG "). diff --git a/src/gd_v.erl b/src/gd_v.erl index 1e50284..b714b66 100644 --- a/src/gd_v.erl +++ b/src/gd_v.erl @@ -1,5 +1,5 @@ -module(gd_v). --vsn("0.8.1"). +-vsn("0.9.0"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index 5b2a306..a0bc9a4 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -1,5 +1,5 @@ -module(gd_v_call). --vsn("0.8.1"). +-vsn("0.9.0"). -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 f3e625e..fc95568 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -1,5 +1,5 @@ -module(gd_v_devman). --vsn("0.8.1"). +-vsn("0.9.0"). -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 4ae4abf..0657f81 100644 --- a/src/gd_v_netman.erl +++ b/src/gd_v_netman.erl @@ -1,5 +1,5 @@ -module(gd_v_netman). --vsn("0.8.1"). +-vsn("0.9.0"). -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 c4e4f22..abc325e 100644 --- a/src/gd_v_wallman.erl +++ b/src/gd_v_wallman.erl @@ -13,7 +13,7 @@ -module(gd_v_wallman). --vsn("0.8.1"). +-vsn("0.9.0"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). diff --git a/zomp.meta b/zomp.meta index 8dd6812..7601125 100644 --- a/zomp.meta +++ b/zomp.meta @@ -1,10 +1,10 @@ {name,"GajuDesk"}. {type,gui}. {modules,[]}. -{prefix,"gd"}. {author,"Craig Everett"}. +{prefix,"gd"}. {desc,"A desktop client for the Gajumaru network of blockchain networks"}. -{package_id,{"otpr","gajudesk",{0,8,1}}}. +{package_id,{"otpr","gajudesk",{0,9,0}}}. {deps,[{"otpr","hakuzaru",{0,8,2}}, {"otpr","zxwidgets",{1,1,0}}, {"otpr","eblake2",{1,0,1}}, -- 2.30.2 From 97589a1da51962889d7c3474848a41e106b8f535 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Sun, 10 May 2026 13:31:57 +0900 Subject: [PATCH 36/37] Remove wx logging junk --- src/gd_v_call.erl | 13 ++++++++----- src/gd_v_devman.erl | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl index a0bc9a4..7f3f084 100644 --- a/src/gd_v_call.erl +++ b/src/gd_v_call.erl @@ -276,7 +276,8 @@ handle_cast(Unexpected, State) -> handle_info(retire, State) -> - retire(State); + ok = retire(State), + {noreply, State}; handle_info(Unexpected, State) -> ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), {noreply, State}. @@ -295,7 +296,8 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, ok = copy(State), {noreply, State}; handle_event(#wx{event = #wxClose{}}, State) -> - retire(State); + ok = retire(State), + {noreply, State}; handle_event(Event, State) -> ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. @@ -305,11 +307,12 @@ code_change(_, State, _) -> {ok, State}. -retire(State = #s{frame = Frame}) -> - ok = wxWindow:destroy(Frame), - {stop, normal, State}. +retire(#s{frame = Frame}) -> + wxWindow:destroy(Frame). +terminate(wx_deleted, _) -> + wx:destroy(); terminate(Reason, State) -> ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), wx:destroy(). diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index fc95568..b7a7405 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -298,6 +298,8 @@ code_change(_, State, _) -> {ok, State}. +terminate(wx_deleted, _) -> + wx:destroy(); terminate(Reason, State) -> ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), wx:destroy(). -- 2.30.2 From 46537a896f6024d5a504580ffa02bd0721eff45e Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Sun, 10 May 2026 15:35:31 +0900 Subject: [PATCH 37/37] Update deps --- zomp.meta | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zomp.meta b/zomp.meta index 7601125..df284e2 100644 --- a/zomp.meta +++ b/zomp.meta @@ -1,11 +1,11 @@ {name,"GajuDesk"}. {type,gui}. {modules,[]}. -{author,"Craig Everett"}. {prefix,"gd"}. +{author,"Craig Everett"}. {desc,"A desktop client for the Gajumaru network of blockchain networks"}. {package_id,{"otpr","gajudesk",{0,9,0}}}. -{deps,[{"otpr","hakuzaru",{0,8,2}}, +{deps,[{"otpr","hakuzaru",{0,9,0}}, {"otpr","zxwidgets",{1,1,0}}, {"otpr","eblake2",{1,0,1}}, {"otpr","base58",{0,1,1}}, -- 2.30.2