Browse Source

First Commit of Transfer Account Wizard.

Ugochukwu Mmaduekwe 7 years ago
parent
commit
a23f97e5bf

+ 206 - 161
src/gui/UCTRLWallet.pas

@@ -9,7 +9,7 @@ interface
 uses
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
   ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
   ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
-  UAccounts, UDataSources, UNode, UWIZSendPASC{, UWIZTransferAccount};
+  UAccounts, UDataSources, UNode, UWIZSendPASC, UWIZTransferAccount;
 
 
 type
 type
 
 
@@ -66,20 +66,29 @@ type
     procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
     procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
     procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
     procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
     procedure RefreshMyAccountsCombo;
     procedure RefreshMyAccountsCombo;
+    function GetAccNoWithoutChecksum(constref ARow: variant): cardinal; inline;
+    function GetAccounts(const AccountNumbers: TArray<cardinal>): TArray<TAccount>;
   protected
   protected
     procedure ActivateFirstTime; override;
     procedure ActivateFirstTime; override;
     procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnNodeBlocksChanged(Sender: TObject);
     procedure OnNodeBlocksChanged(Sender: TObject);
     procedure OnNodeNewOperation(Sender: TObject);
     procedure OnNodeNewOperation(Sender: TObject);
     procedure OnAccountsUpdated(Sender: TObject);
     procedure OnAccountsUpdated(Sender: TObject);
-    procedure OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
-    procedure OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+    procedure OnAccountsSelected(Sender: TObject;
+      constref ASelection: TVisualGridSelection);
+    procedure OnOperationSelected(Sender: TObject;
+      constref ASelection: TVisualGridSelection);
+    procedure OnPrepareAccountPopupMenu(Sender: TObject;
+      constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+    procedure OnPrepareOperationsPopupMenu(Sender: TObject;
+      constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
   public
   public
-    property AccountsMode: TCTRLWalletAccountsMode read FAccountsMode write SetAccountsMode;
-    property OperationsMode: TCTRLWalletOperationsMode read FOperationsMode write SetOperationsMode;
-    property OperationsHistory: TCTRLWalletOperationsHistory read FOperationsHistory write SetOperationsHistory;
+    property AccountsMode: TCTRLWalletAccountsMode
+      read FAccountsMode write SetAccountsMode;
+    property OperationsMode: TCTRLWalletOperationsMode
+      read FOperationsMode write SetOperationsMode;
+    property OperationsHistory: TCTRLWalletOperationsHistory
+      read FOperationsHistory write SetOperationsHistory;
   end;
   end;
 
 
 implementation
 implementation
@@ -115,30 +124,34 @@ begin
   FAccountsGrid.AutoPageSize := True;
   FAccountsGrid.AutoPageSize := True;
   FAccountsGrid.SelectionType := stMultiRow;
   FAccountsGrid.SelectionType := stMultiRow;
   FAccountsGrid.DeselectionType := dtDefault;
   FAccountsGrid.DeselectionType := dtDefault;
-  FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
-  with FAccountsGrid.AddColumn('Account') do begin
+  FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing,
+    vgoSortDirectionAllowNone, vgoAutoHidePaging];
+  with FAccountsGrid.AddColumn('Account') do
+  begin
     Binding := 'AccountNumber';
     Binding := 'AccountNumber';
     SortBinding := 'AccountNumber';
     SortBinding := 'AccountNumber';
     DisplayBinding := 'Account';
     DisplayBinding := 'Account';
     Width := 100;
     Width := 100;
     HeaderFontStyles := [fsBold];
     HeaderFontStyles := [fsBold];
     DataFontStyles := [fsBold];
     DataFontStyles := [fsBold];
-    Filters:=SORTABLE_NUMERIC_FILTER;
+    Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FAccountsGrid.AddColumn('Name') do begin
-    StretchedToFill := true;
+  with FAccountsGrid.AddColumn('Name') do
+  begin
+    StretchedToFill := True;
     HeaderAlignment := taCenter;
     HeaderAlignment := taCenter;
-    Filters:=SORTABLE_TEXT_FILTER;
+    Filters := SORTABLE_TEXT_FILTER;
   end;
   end;
-  with FAccountsGrid.AddColumn('Balance') do begin
+  with FAccountsGrid.AddColumn('Balance') do
+  begin
     Binding := 'BalanceDecimal';
     Binding := 'BalanceDecimal';
     SortBinding := 'Balance';
     SortBinding := 'Balance';
     DisplayBinding := 'Balance';
     DisplayBinding := 'Balance';
     Width := 100;
     Width := 100;
-    HeaderAlignment:=taRightJustify;
-    DataAlignment:=taRightJustify;
+    HeaderAlignment := taRightJustify;
+    DataAlignment := taRightJustify;
     Renderer := TCellRenderers.PASC;
     Renderer := TCellRenderers.PASC;
-    Filters:=SORTABLE_NUMERIC_FILTER;
+    Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
 
 
   FAccountsGrid.OnSelection := OnAccountsSelected;
   FAccountsGrid.OnSelection := OnAccountsSelected;
@@ -151,32 +164,38 @@ begin
   FOperationsGrid.AutoPageSize := True;
   FOperationsGrid.AutoPageSize := True;
   FOperationsGrid.SelectionType := stRow;
   FOperationsGrid.SelectionType := stRow;
   FOperationsGrid.DeselectionType := dtDefault;
   FOperationsGrid.DeselectionType := dtDefault;
-  FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
-  with FOperationsGrid.AddColumn('Time') do begin
+  FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing,
+    vgoSortDirectionAllowNone, vgoAutoHidePaging];
+  with FOperationsGrid.AddColumn('Time') do
+  begin
     SortBinding := 'UnixTime';
     SortBinding := 'UnixTime';
     DisplayBinding := 'UnixTime';
     DisplayBinding := 'UnixTime';
-    Renderer:=TCellRenderers.OperationTime;
+    Renderer := TCellRenderers.OperationTime;
     Width := 130;
     Width := 130;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Block') do begin
+  with FOperationsGrid.AddColumn('Block') do
+  begin
     Binding := 'BlockLocation';
     Binding := 'BlockLocation';
     SortBinding := 'BlockLocationSortable';
     SortBinding := 'BlockLocationSortable';
-    AutoWidth := true;
+    AutoWidth := True;
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Account') do begin
+  with FOperationsGrid.AddColumn('Account') do
+  begin
     Binding := 'AccountNumber';
     Binding := 'AccountNumber';
     DisplayBinding := 'Account';
     DisplayBinding := 'Account';
     Width := 100;
     Width := 100;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Type') do begin
+  with FOperationsGrid.AddColumn('Type') do
+  begin
     Sanitizer := TCellRenderers.OperationTypeSanitizer;
     Sanitizer := TCellRenderers.OperationTypeSanitizer;
     Width := 150;
     Width := 150;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Amount') do begin
+  with FOperationsGrid.AddColumn('Amount') do
+  begin
     Binding := 'AmountDecimal';
     Binding := 'AmountDecimal';
     SortBinding := 'Amount';
     SortBinding := 'Amount';
     DisplayBinding := 'Amount';
     DisplayBinding := 'Amount';
@@ -185,38 +204,43 @@ begin
     Renderer := TCellRenderers.PASC;
     Renderer := TCellRenderers.PASC;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Fee') do begin
+  with FOperationsGrid.AddColumn('Fee') do
+  begin
     Binding := 'FeeDecimal';
     Binding := 'FeeDecimal';
     SortBinding := 'Fee';
     SortBinding := 'Fee';
     DisplayBinding := 'Fee';
     DisplayBinding := 'Fee';
-    AutoWidth := true;
-    HeaderAlignment:=taRightJustify;
-    DataAlignment:=taRightJustify;
+    AutoWidth := True;
+    HeaderAlignment := taRightJustify;
+    DataAlignment := taRightJustify;
     Renderer := TCellRenderers.PASC;
     Renderer := TCellRenderers.PASC;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Balance') do begin
+  with FOperationsGrid.AddColumn('Balance') do
+  begin
     Binding := 'BalanceDecimal';
     Binding := 'BalanceDecimal';
     SortBinding := 'Balance';
     SortBinding := 'Balance';
     DisplayBinding := 'Balance';
     DisplayBinding := 'Balance';
     Width := 100;
     Width := 100;
-    HeaderAlignment:=taRightJustify;
-    DataAlignment:=taRightJustify;
+    HeaderAlignment := taRightJustify;
+    DataAlignment := taRightJustify;
     Renderer := TCellRenderers.PASC;
     Renderer := TCellRenderers.PASC;
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Payload') do begin
-    AutoWidth := true;
+  with FOperationsGrid.AddColumn('Payload') do
+  begin
+    AutoWidth := True;
     Renderer := TCellRenderers.Payload;
     Renderer := TCellRenderers.Payload;
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('OPHASH') do begin
+  with FOperationsGrid.AddColumn('OPHASH') do
+  begin
     Width := 80;
     Width := 80;
     Renderer := TCellRenderers.OPHASH;
     Renderer := TCellRenderers.OPHASH;
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
   end;
   end;
-  with FOperationsGrid.AddColumn('Description') do begin
-    StretchedToFill := true;
+  with FOperationsGrid.AddColumn('Description') do
+  begin
+    StretchedToFill := True;
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
   end;
   end;
   FOperationsGrid.OnSelection := OnOperationSelected;
   FOperationsGrid.OnSelection := OnOperationSelected;
@@ -230,7 +254,7 @@ begin
 
 
   // duration combo
   // duration combo
   cmbDuration := TComboBox.Create(FOperationsGrid);
   cmbDuration := TComboBox.Create(FOperationsGrid);
-  cmbDuration.ReadOnly:= true;
+  cmbDuration.ReadOnly := True;
   cmbDuration.Items.BeginUpdate;
   cmbDuration.Items.BeginUpdate;
   try
   try
     cmbDuration.AddItem('30 Days', TObject(woh30Days));
     cmbDuration.AddItem('30 Days', TObject(woh30Days));
@@ -269,71 +293,134 @@ end;
 
 
 procedure TCTRLWallet.RefreshMyAccountsCombo;
 procedure TCTRLWallet.RefreshMyAccountsCombo;
 var
 var
-  i : Integer;
-  selectFirst, selectLast : boolean;
+  i: integer;
+  selectFirst, selectLast: boolean;
   last_key: TAccountKey;
   last_key: TAccountKey;
-  key : TWalletKey;
-  str : AnsiString;
+  key: TWalletKey;
+  str: ansistring;
 begin
 begin
   // determine current selection
   // determine current selection
-  if cbAccounts.ItemIndex >= 1 then begin
-    if cbAccounts.ItemIndex < cbAccounts.Items.Count - 1 then begin
-      last_key := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]).Value;
-      selectFirst := false;
-      selectLast := false;
-    end else begin
-      selectFirst := false;
-      selectLast := true;
+  if cbAccounts.ItemIndex >= 1 then
+  begin
+    if cbAccounts.ItemIndex < cbAccounts.Items.Count - 1 then
+    begin
+      last_key := TBox<TAccountKey>(
+        cbAccounts.Items.Objects[cbAccounts.ItemIndex]).Value;
+      selectFirst := False;
+      selectLast := False;
+    end
+    else
+    begin
+      selectFirst := False;
+      selectLast := True;
     end;
     end;
-  end else begin
-    selectFirst := true;
-    selectLast := false;
+  end
+  else
+  begin
+    selectFirst := True;
+    selectLast := False;
   end;
   end;
 
 
   // update combo items
   // update combo items
   cbAccounts.items.BeginUpdate;
   cbAccounts.items.BeginUpdate;
-  Try
+  try
     // free existing items
     // free existing items
     for i := 0 to cbAccounts.Items.Count - 1 do
     for i := 0 to cbAccounts.Items.Count - 1 do
       cbAccounts.Items.Objects[i].Free;
       cbAccounts.Items.Objects[i].Free;
     cbAccounts.Items.Clear;
     cbAccounts.Items.Clear;
     // add new items
     // add new items
-    For i:=0 to TWallet.Keys.Count-1 do begin
+    for i := 0 to TWallet.Keys.Count - 1 do
+    begin
       // get i'th key
       // get i'th key
       key := TWallet.Keys.Key[i];
       key := TWallet.Keys.Key[i];
       // fix name
       // fix name
-      if (key.Name='') then begin
-        str := 'Sha256=' + TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString( key.AccountKey ) ) );
-      end else begin
+      if (key.Name = '') then
+      begin
+        str := 'Sha256=' + TCrypto.ToHexaString(TCrypto.DoSha256(
+          TAccountComp.AccountKey2RawString(key.AccountKey)));
+      end
+      else
+      begin
         str := key.Name;
         str := key.Name;
       end;
       end;
-      if Not Assigned(key.PrivateKey) then str := str + '(*)';
+      if not Assigned(key.PrivateKey) then
+        str := str + '(*)';
       cbAccounts.Items.AddObject(str, TBox<TAccountKey>.Create(key.AccountKey));
       cbAccounts.Items.AddObject(str, TBox<TAccountKey>.Create(key.AccountKey));
     end;
     end;
-    cbAccounts.Items.InsertObject(0,'Show All', TBox<TAccountKey>.Create);
-    cbAccounts.Items.AddObject('Get An Account',TBox<TAccountKey>.Create);
-  Finally
+    cbAccounts.Items.InsertObject(0, 'Show All', TBox<TAccountKey>.Create);
+    cbAccounts.Items.AddObject('Get An Account', TBox<TAccountKey>.Create);
+  finally
     cbAccounts.Items.EndUpdate;
     cbAccounts.Items.EndUpdate;
-  End;
+  end;
   // re-select previous selection
   // re-select previous selection
   if selectFirst then
   if selectFirst then
     cbAccounts.ItemIndex := 0
     cbAccounts.ItemIndex := 0
   else if selectLast then
   else if selectLast then
     cbAccounts.ItemIndex := cbAccounts.Items.Count - 1
     cbAccounts.ItemIndex := cbAccounts.Items.Count - 1
-  else begin
-    for i := 1 to cbAccounts.Items.Count - 2 do begin
-       if TAccountKeyEqualityComparer.AreEqual(TBox<TAccountKey>( cbAccounts.Items.Objects[i] ).Value, last_key) then begin
-         cbAccounts.ItemIndex := i;
-         exit;
-       end;
+  else
+  begin
+    for i := 1 to cbAccounts.Items.Count - 2 do
+    begin
+      if TAccountKeyEqualityComparer.AreEqual(TBox<TAccountKey>(
+        cbAccounts.Items.Objects[i]).Value, last_key) then
+      begin
+        cbAccounts.ItemIndex := i;
+        exit;
+      end;
     end;
     end;
   end;
   end;
 end;
 end;
 
 
+function TCTRLWallet.GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
+begin
+  Result := ARow.__KEY;
+end;
+
+//function GetAccNoWithCheckSum(constref ARow: variant): string;
+//begin
+//  Result := ARow.Account;
+//end;
+
+function TCTRLWallet.GetAccounts(const AccountNumbers: TArray<cardinal>): TArray<TAccount>;
+var
+  acc: TAccount;
+  safeBox: TPCSafeBox;
+  keys: TOrderedAccountKeysList;
+  LContainer: Generics.Collections.TList<TAccount>;
+  i: integer;
+begin
+  LContainer := Generics.Collections.TList<TAccount>.Create();
+  keys := TWallet.keys.AccountsKeyList;
+  safeBox := TUserInterface.Node.Bank.safeBox;
+  safeBox.StartThreadSafe;
+  try
+    LContainer.Clear;
+    try
+      // load selected user accounts
+      for i := Low(AccountNumbers) to High(AccountNumbers) do
+      begin
+        acc := safeBox.Account(AccountNumbers[i]);
+        if keys.IndexOfAccountKey(acc.accountInfo.accountKey) >= 0 then
+        begin
+          LContainer.Add(acc);
+        end;
+      end;
+    finally
+      safeBox.EndThreadSave;
+    end;
+    Result := LContainer.ToArray;
+  finally
+    LContainer.Free;
+  end;
+
+end;
+
 procedure TCTRLWallet.SetAccountsMode(AMode: TCTRLWalletAccountsMode);
 procedure TCTRLWallet.SetAccountsMode(AMode: TCTRLWalletAccountsMode);
-var sel1 : TVisualGridSelection; sel2 : TRect;
+var
+  sel1: TVisualGridSelection;
+  sel2: TRect;
 begin
 begin
-  FAccountsMode:= AMode;
+  FAccountsMode := AMode;
   paAccounts.RemoveAllControls(False);
   paAccounts.RemoveAllControls(False);
   case AMode of
   case AMode of
     wamMyAccounts:
     wamMyAccounts:
@@ -441,11 +528,10 @@ begin
         selectedAccounts.Add(acc);
         selectedAccounts.Add(acc);
     end;
     end;
     FOperationsDataSource.Accounts := selectedAccounts.ToArray;
     FOperationsDataSource.Accounts := selectedAccounts.ToArray;
-    FOperationsGrid.Caption.Text:= IIF(
-       ASelection.RowCount = 1,
-       Format('Account: %s', [TAccountComp.AccountNumberToAccountTxtNumber( selectedAccounts[0] )]),
-       'Selected Accounts'
-    ) ;
+    FOperationsGrid.Caption.Text :=
+      IIF(ASelection.RowCount = 1, Format('Account: %s',
+      [TAccountComp.AccountNumberToAccountTxtNumber(selectedAccounts[0])]),
+      'Selected Accounts');
     FOperationsGrid.RefreshGrid;
     FOperationsGrid.RefreshGrid;
   end
   end
   else
   else
@@ -454,7 +540,8 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TCTRLWallet.OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+procedure TCTRLWallet.OnOperationSelected(Sender: TObject;
+  constref ASelection: TVisualGridSelection);
 var
 var
   row: longint;
   row: longint;
   v: variant;
   v: variant;
@@ -472,17 +559,21 @@ end;
 
 
 procedure TCTRLWallet.cbAccountsChange(Sender: TObject);
 procedure TCTRLWallet.cbAccountsChange(Sender: TObject);
 var
 var
-  index : Integer;
-  sel : TBox<TAccountKey>;
+  index: integer;
+  sel: TBox<TAccountKey>;
 begin
 begin
   index := cbAccounts.ItemIndex;
   index := cbAccounts.ItemIndex;
-  if cbAccounts.ItemIndex < 0 then exit;
+  if cbAccounts.ItemIndex < 0 then
+    exit;
   if index = 0 then
   if index = 0 then
     FAccountsDataSource.FilterKeys := TWallet.Keys.AccountsKeyList.ToArray
     FAccountsDataSource.FilterKeys := TWallet.Keys.AccountsKeyList.ToArray
-  else if index = cbAccounts.Items.Count - 1 then begin
-    AccountsMode:= wamFirstAccount;
+  else if index = cbAccounts.Items.Count - 1 then
+  begin
+    AccountsMode := wamFirstAccount;
     exit;
     exit;
-  end else begin
+  end
+  else
+  begin
     sel := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]);
     sel := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]);
     FAccountsDataSource.FilterKeys := TArray<TAccountKey>.Create(sel.Value);
     FAccountsDataSource.FilterKeys := TArray<TAccountKey>.Create(sel.Value);
   end;
   end;
@@ -506,7 +597,8 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TCTRLWallet.OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+procedure TCTRLWallet.OnPrepareAccountPopupMenu(Sender: TObject;
+  constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
 begin
 begin
   miSep1.Visible := ASelection.RowCount = 1;
   miSep1.Visible := ASelection.RowCount = 1;
   miAccountInfo.Visible := ASelection.RowCount = 1;
   miAccountInfo.Visible := ASelection.RowCount = 1;
@@ -523,56 +615,6 @@ begin
 end;
 end;
 
 
 procedure TCTRLWallet.miSendPASCClick(Sender: TObject);
 procedure TCTRLWallet.miSendPASCClick(Sender: TObject);
-
-  function GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
-  begin
-    if not TAccountComp.AccountTxtNumberToAccountNumber(ARow.Account, Result) then
-    begin
-      raise Exception.Create(
-        'Internal Error: Unable to parse account number from table row');
-    end;
-  end;
-
-  function GetAccNoWithCheckSum(constref ARow: variant): string;
-  begin
-    Result := ARow.Account;
-  end;
-
-  function GetAccounts(AccountNumbers: TArray<cardinal>): TArray<TAccount>;
-  var
-    acc: TAccount;
-    safeBox: TPCSafeBox;
-    keys: TOrderedAccountKeysList;
-    LContainer: Generics.Collections.TList<TAccount>;
-    i: integer;
-  begin
-    LContainer := Generics.Collections.TList<TAccount>.Create();
-    keys := TWallet.keys.AccountsKeyList;
-    safeBox := TUserInterface.Node.Bank.safeBox;
-    safeBox.StartThreadSafe;
-    try
-      LContainer.Clear;
-      try
-
-        // load selected user accounts
-        for i := 0 to High(AccountNumbers) do
-        begin
-          acc := safeBox.Account(AccountNumbers[i]);
-          if keys.IndexOfAccountKey(acc.accountInfo.accountKey) >= 0 then
-          begin
-            LContainer.Add(acc);
-          end;
-        end;
-      finally
-        safeBox.EndThreadSave;
-      end;
-      Result := LContainer.ToArray;
-    finally
-      LContainer.Free;
-    end;
-
-  end;
-
 var
 var
   Scoped: TDisposables;
   Scoped: TDisposables;
   wiz: TWIZSendPASCWizard;
   wiz: TWIZSendPASCWizard;
@@ -592,37 +634,40 @@ begin
 end;
 end;
 
 
 procedure TCTRLWallet.miTransferAccountsClick(Sender: TObject);
 procedure TCTRLWallet.miTransferAccountsClick(Sender: TObject);
-//var
-//  Scoped: TDisposables;
-//  wiz: TWIZTransferAccountWizard;
-//  model: TWIZTransferAccountModel;
-//  auxC: cardinal;
+var
+  Scoped: TDisposables;
+  wiz: TWIZTransferAccountWizard;
+  model: TWIZTransferAccountModel;
+  AccountNumbersWithoutChecksum: TArray<cardinal>;
 begin
 begin
-  //wiz := Scoped.AddObject(TWIZTransferAccountWizard.Create(nil)) as
-  //  TWIZTransferAccountWizard;
-  //model := Scoped.AddObject(TWIZTransferAccountModel.Create(nil)) as
-  //  TWIZTransferAccountModel;
-  //
-  //if not TAccountComp.AccountTxtNumberToAccountNumber(
-  //  FAccountsGrid.SelectedRows[0].Account, auxC) then
-  //begin
-  //  raise Exception.Create(
-  //    'Internal Error: Unable to parse account number from input');
-  //end;
-  //
-  //model.SelectedAccount := TNode.Node.Operations.SafeBoxTransaction.Account(auxC);
-  //wiz.Start(model);
+  wiz := Scoped.AddObject(TWIZTransferAccountWizard.Create(nil)) as
+    TWIZTransferAccountWizard;
+  model := Scoped.AddObject(TWIZTransferAccountModel.Create(nil)) as
+    TWIZTransferAccountModel;
+
+  AccountNumbersWithoutChecksum :=
+    TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
+    GetAccNoWithoutChecksum);
+
+  model.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
+  model.SelectedIndex := 0;
+  wiz.Start(model);
 end;
 end;
 
 
-procedure TCTRLWallet.OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+procedure TCTRLWallet.OnPrepareOperationsPopupMenu(Sender: TObject;
+  constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
 begin
 begin
-  if (ASelection.RowCount <> 1) OR ((ASelection.RowCount = 1) and (FOperationsGrid.SelectedRows[0].__KEY <> Variant(nil))) then begin
-    miSep2.Visible := true;
-    miOperationInfo.Visible := true;
+  if (ASelection.RowCount <> 1) or ((ASelection.RowCount = 1) and
+    (FOperationsGrid.SelectedRows[0].__KEY <> variant(nil))) then
+  begin
+    miSep2.Visible := True;
+    miOperationInfo.Visible := True;
     APopupMenu := mnuOperationsPopup;
     APopupMenu := mnuOperationsPopup;
-  end else begin
-    miSep2.Visible := false;
-    miOperationInfo.Visible := false;
+  end
+  else
+  begin
+    miSep2.Visible := False;
+    miOperationInfo.Visible := False;
     APopupMenu := nil; // is empty, so dont show
     APopupMenu := nil; // is empty, so dont show
   end;
   end;
 end;
 end;

+ 0 - 1
src/gui/wizards/UWIZSendPASC.pas

@@ -62,7 +62,6 @@ uses
   UECIES,
   UECIES,
   UAES,
   UAES,
   UWIZSendPASC_Start,
   UWIZSendPASC_Start,
-  UWIZSendPASC_Transaction,
   UWIZSendPASC_Confirmation;
   UWIZSendPASC_Confirmation;
 
 
 { TWIZSendPASCWizard }
 { TWIZSendPASCWizard }

+ 0 - 1
src/gui/wizards/UWIZSendPASC_Confirmation.lfm

@@ -6,7 +6,6 @@ object WIZSendPASC_Confirmation: TWIZSendPASC_Confirmation
   Caption = 'WIZSendPASC_Confirmation'
   Caption = 'WIZSendPASC_Confirmation'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
   Visible = False
   Visible = False
   object GroupBox1: TGroupBox
   object GroupBox1: TGroupBox
     Left = 10
     Left = 10

+ 0 - 1
src/gui/wizards/UWIZSendPASC_Start.lfm

@@ -6,7 +6,6 @@ object WIZSendPASC_Start: TWIZSendPASC_Start
   Caption = 'WIZSendPASC_Start'
   Caption = 'WIZSendPASC_Start'
   ClientHeight = 261
   ClientHeight = 261
   ClientWidth = 429
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
   Visible = False
   Visible = False
   object gpSender: TGroupBox
   object gpSender: TGroupBox
     Left = 4
     Left = 4

+ 0 - 1
src/gui/wizards/UWIZSendPASC_Transaction.lfm

@@ -7,7 +7,6 @@ object WIZSendPASC_Transaction: TWIZSendPASC_Transaction
   Caption = 'WIZSendPASC_Transaction'
   Caption = 'WIZSendPASC_Transaction'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
   Visible = False
   Visible = False
   object gbTransaction: TGroupBox
   object gbTransaction: TGroupBox
     Left = 22
     Left = 22

+ 1 - 0
src/gui/wizards/UWIZSendPASC_TransactionPayload.lfm

@@ -7,6 +7,7 @@ object WIZSendPASC_TransactionPayload: TWIZSendPASC_TransactionPayload
   Caption = 'Form1'
   Caption = 'Form1'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
+  LCLVersion = '1.8.1.0'
   Visible = False
   Visible = False
   object grpPayload: TGroupBox
   object grpPayload: TGroupBox
     Left = 8
     Left = 8

+ 1 - 1
src/gui/wizards/UWIZSendPASC_TransactionPayload.pas

@@ -14,7 +14,7 @@ interface
 uses
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
   ExtCtrls, Buttons, UCommon, UCommon.Collections,
   ExtCtrls, Buttons, UCommon, UCommon.Collections,
-  UWizard, UWIZSendPASC, UWIZSendPASC_Confirmation;
+  UWizard, UWIZSendPASC;
 
 
 type
 type
 
 

+ 102 - 0
src/gui/wizards/UWIZTransferAccount.pas

@@ -0,0 +1,102 @@
+unit UWIZTransferAccount;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Dialogs, UCrypto, UWizard, UAccounts, LCLType;
+
+type
+
+  { TWIZTransferAccountModel }
+  TWIZPayloadEncryptionMode = (akaEncryptWithOldEC, akaEncryptWithEC,
+    akaEncryptWithPassword, akaNotEncrypt);
+
+  TWIZTransferAccountModel = class(TComponent)
+  public
+    DefaultFee: int64;
+    NewPublicKey, Payload, EncryptionPassword: string;
+    SelectedIndex: integer;
+    AccountKey: TAccountKey;
+    EncodedPayload: TRawBytes;
+    SignerAccount: TAccount;
+    SelectedAccounts, SortedAccounts: TArray<TAccount>;
+    PayloadEncryptionMode: TWIZPayloadEncryptionMode;
+  end;
+
+  { TWIZTransferAccountWizard }
+
+  TWIZTransferAccountWizard = class(TWizard<TWIZTransferAccountModel>)
+    // private
+    //procedure TransferAccount();
+  public
+    constructor Create(AOwner: TComponent); override;
+    function DetermineHasNext: boolean; override;
+    function DetermineHasPrevious: boolean; override;
+    function FinishRequested(out message: ansistring): boolean; override;
+    function CancelRequested(out message: ansistring): boolean; override;
+  end;
+
+implementation
+
+uses
+  UBlockChain,
+  UOpTransaction,
+  UNode,
+  UConst,
+  UWallet,
+  UECIES,
+  UAES,
+  UWIZTransferAccount_Start,
+  UWIZTransferAccount_Confirmation;
+
+{ TWIZTransferAccountWizard }
+
+constructor TWIZTransferAccountWizard.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner, [TWIZTransferAccount_Start,
+    TWIZTransferAccount_Confirmation]);
+  TitleText := 'Transfer Account';
+  FinishText := 'Transfer Account';
+end;
+
+function TWIZTransferAccountWizard.DetermineHasNext: boolean;
+begin
+  Result := not (CurrentScreen is TWIZTransferAccount_Confirmation);
+end;
+
+function TWIZTransferAccountWizard.DetermineHasPrevious: boolean;
+begin
+  Result := inherited DetermineHasPrevious;
+end;
+
+function TWIZTransferAccountWizard.FinishRequested(out message: ansistring): boolean;
+begin
+  // Execute the Transfer Account Action here
+  raise ENotImplemented.Create('Not yet implemented.');
+  //try
+  //  Result := True;
+  //  // TransferAccount();
+  //except
+  //  On E: Exception do
+  //  begin
+  //    Result := False;
+  //    message := E.ToString;
+  //  end;
+  //end;
+end;
+
+function TWIZTransferAccountWizard.CancelRequested(out message: ansistring): boolean;
+begin
+  Result := True;
+end;
+
+end.

+ 47 - 0
src/gui/wizards/UWIZTransferAccount_Confirmation.lfm

@@ -0,0 +1,47 @@
+object WIZTransferAccount_Confirmation: TWIZTransferAccount_Confirmation
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZTransferAccount_Confirmation'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object GroupBox1: TGroupBox
+    Left = 10
+    Height = 232
+    Top = 8
+    Width = 408
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    Caption = 'Confirm Transfer Transaction'
+    ClientHeight = 212
+    ClientWidth = 404
+    TabOrder = 0
+    object paGrid: TPanel
+      Left = 8
+      Height = 152
+      Top = 48
+      Width = 382
+      Anchors = [akTop, akLeft, akRight, akBottom]
+      BevelOuter = bvNone
+      Caption = 'GRID PANEL'
+      TabOrder = 0
+    end
+    object Label1: TLabel
+      Left = 8
+      Height = 15
+      Top = 16
+      Width = 84
+      Caption = 'Signer Account:'
+      ParentColor = False
+    end
+    object lblSgnAcc: TLabel
+      Left = 112
+      Height = 15
+      Top = 16
+      Width = 53
+      Caption = 'lblSgnAcc'
+      ParentColor = False
+    end
+  end
+end

+ 137 - 0
src/gui/wizards/UWIZTransferAccount_Confirmation.pas

@@ -0,0 +1,137 @@
+unit UWIZTransferAccount_Confirmation;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UVisualGrid, UCellRenderers, UCommon.Data, UWizard, UWIZTransferAccount;
+
+type
+
+  { TWIZTransferAccount_Confirmation }
+
+  TWIZTransferAccount_Confirmation = class(TWizardForm<TWIZTransferAccountModel>)
+    GroupBox1: TGroupBox;
+    Label1: TLabel;
+    lblSgnAcc: TLabel;
+    paGrid: TPanel;
+  private
+    FSendersGrid : TVisualGrid;
+  public
+    procedure OnPresent; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+type
+
+  { TAccountSenderDataSource }
+
+  TAccountSenderDataSource = class(TAccountsDataSourceBase)
+    private
+      FModel : TWIZTransferAccountModel;
+    protected
+      function GetColumns : TDataColumns; override;
+    public
+      property Model : TWIZTransferAccountModel read FModel write FModel;
+      procedure FetchAll(const AContainer : TList<TAccount>); override;
+      function GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant; override;
+  end;
+
+{ TWIZTransferAccount_Confirmation }
+
+procedure TWIZTransferAccount_Confirmation.OnPresent;
+var
+  data : TAccountSenderDataSource;
+begin
+  FSendersGrid := TVisualGrid.Create(Self);
+  FSendersGrid.CanSearch:= False;
+  FSendersGrid.SortMode := smMultiColumn;
+  FSendersGrid.FetchDataInThread := False;
+  FSendersGrid.AutoPageSize := True;
+  FSendersGrid.SelectionType := stNone;
+  FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
+  with FSendersGrid.AddColumn('Account') do begin
+    Binding := 'Account';
+    Filters := SORTABLE_NUMERIC_FILTER;
+    Width := 100;
+    HeaderFontStyles := [fsBold];
+    DataFontStyles := [fsBold];
+  end;
+  with FSendersGrid.AddColumn('Current Public Key') do begin
+    Binding := 'CurrentPublicKey';
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+   with FSendersGrid.AddColumn('New Public Key') do begin
+    Binding := 'NewPublicKey';
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+  with FSendersGrid.AddColumn('Fee') do begin
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+
+   data := TAccountSenderDataSource.Create(FSendersGrid);
+   data.Model := Model;
+   FSendersGrid.DataSource := data;
+   paGrid.AddControlDockCenter(FSendersGrid);
+   lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.SignerAccount.account);
+end;
+
+{ TAccountSenderDataSource }
+
+function TAccountSenderDataSource.GetColumns : TDataColumns;
+begin
+  Result := TDataColumns.Create(
+    TDataColumn.From('Account'),
+    TDataColumn.From('CurrentPublicKey'),
+    TDataColumn.From('NewPublicKey'),
+    TDataColumn.From('Fee')
+  );
+end;
+
+function TAccountSenderDataSource.GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant;
+var
+  index : Integer;
+begin
+   if ABindingName = 'Account' then
+     Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
+   else if ABindingName = 'CurrentPublicKey' then
+     Result := TAccountComp.AccountPublicKeyExport(AItem.accountInfo.accountKey)
+   else if ABindingName = 'NewPublicKey' then
+     Result := Model.NewPublicKey
+     else if ABindingName = 'Fee' then
+     Result := TAccountComp.FormatMoney(Model.DefaultFee)
+   else raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
+end;
+
+
+procedure TAccountSenderDataSource.FetchAll(const AContainer : TList<TAccount>);
+var
+  i: Integer;
+begin
+  for i := Low(Model.SortedAccounts) to High(Model.SortedAccounts) do
+  begin
+    AContainer.Add( Model.SortedAccounts[i] );
+  end;
+end;
+
+
+end.
+

+ 31 - 0
src/gui/wizards/UWIZTransferAccount_Start.lfm

@@ -0,0 +1,31 @@
+object WIZTransferAccount_Start: TWIZTransferAccount_Start
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZTransferAccount_Start'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object grpTransferAccount: TGroupBox
+    Left = 6
+    Height = 248
+    Top = 0
+    Width = 416
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    Caption = 'Transfer Accounts'
+    ClientHeight = 228
+    ClientWidth = 412
+    TabOrder = 0
+    object paGrid: TPanel
+      Left = 6
+      Height = 200
+      Top = 24
+      Width = 402
+      Anchors = [akTop, akLeft, akRight, akBottom]
+      BevelOuter = bvNone
+      Caption = 'GRID PANEL'
+      TabOrder = 0
+    end
+  end
+end

+ 110 - 0
src/gui/wizards/UWIZTransferAccount_Start.pas

@@ -0,0 +1,110 @@
+unit UWIZTransferAccount_Start;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UVisualGrid, UCommon.Data, UCellRenderers,
+  UWizard, UWIZTransferAccount, UWIZTransferAccount_Transaction, UWIZSendPASC_Confirmation;
+
+type
+
+  { TWIZTransferAccount_Start }
+
+  TWIZTransferAccount_Start = class(TWizardForm<TWIZTransferAccountModel>)
+    grpTransferAccount: TGroupBox;
+    paGrid: TPanel;
+  private
+    FSendersGrid: TVisualGrid;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+  end;
+
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, USettings, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+type
+
+  { TAccountSenderDataSource }
+
+  TAccountSenderDataSource = class(TAccountsDataSourceBase)
+  private
+    FModel: TWIZTransferAccountModel;
+  public
+    property Model: TWIZTransferAccountModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
+  end;
+
+procedure TAccountSenderDataSource.FetchAll(const AContainer: TList<TAccount>);
+var
+  i: integer;
+begin
+  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+  begin
+    AContainer.Add(Model.SelectedAccounts[i]);
+  end;
+end;
+
+{ TWIZTransferAccount_Start }
+
+procedure TWIZTransferAccount_Start.OnPresent;
+var
+  Data: TAccountSenderDataSource;
+begin
+  FSendersGrid := TVisualGrid.Create(Self);
+  FSendersGrid.CanSearch := False;
+  FSendersGrid.SortMode := smMultiColumn;
+  FSendersGrid.FetchDataInThread := False;
+  FSendersGrid.AutoPageSize := True;
+  FSendersGrid.SelectionType := stNone;
+  FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone,
+    vgoAutoHidePaging];
+  with FSendersGrid.AddColumn('Account') do
+  begin
+    StretchedToFill := True;
+    Binding := 'AccountNumber';
+    SortBinding := 'AccountNumber';
+    DisplayBinding := 'Account';
+    Width := 100;
+    HeaderFontStyles := [fsBold];
+    DataFontStyles := [fsBold];
+    Filters := SORTABLE_NUMERIC_FILTER;
+  end;
+  with FSendersGrid.AddColumn('Balance') do
+  begin
+    Binding := 'BalanceDecimal';
+    SortBinding := 'Balance';
+    DisplayBinding := 'Balance';
+    Width := 100;
+    HeaderAlignment := taRightJustify;
+    DataAlignment := taRightJustify;
+    Renderer := TCellRenderers.PASC;
+    Filters := SORTABLE_NUMERIC_FILTER;
+  end;
+  Data := TAccountSenderDataSource.Create(FSendersGrid);
+  Data.Model := Model;
+  FSendersGrid.DataSource := Data;
+  paGrid.AddControlDockCenter(FSendersGrid);
+end;
+
+procedure TWIZTransferAccount_Start.OnNext;
+begin
+   UpdatePath(ptReplaceAllNext, [TWIZTransferAccount_Transaction, TWIZSendPASC_Confirmation]);
+end;
+
+end.

+ 92 - 0
src/gui/wizards/UWIZTransferAccount_Transaction.lfm

@@ -0,0 +1,92 @@
+object WIZTransferAccount_Transaction: TWIZTransferAccount_Transaction
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = cbSignerAccount
+  Caption = 'WIZTransferAccount_Transaction'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object gbTransaction: TGroupBox
+    Left = 24
+    Height = 192
+    Top = 40
+    Width = 384
+    Caption = 'Transfer Transaction Details'
+    ClientHeight = 172
+    ClientWidth = 380
+    TabOrder = 0
+    object cbSignerAccount: TComboBox
+      Left = 8
+      Height = 23
+      Top = 8
+      Width = 168
+      ItemHeight = 15
+      Items.Strings = (
+        ''
+      )
+      OnChange = cbSignerAccountChange
+      TabOrder = 0
+      Text = 'Select Signer Account'
+    end
+    object lblBalance: TLabel
+      Left = 200
+      Height = 15
+      Top = 12
+      Width = 151
+      Caption = 'Please Select Signer Account'
+      Font.Color = clRed
+      ParentColor = False
+      ParentFont = False
+    end
+    object lblpublickey: TLabel
+      Left = 8
+      Height = 15
+      Top = 48
+      Width = 120
+      Caption = 'New Owner Public Key'
+      ParentColor = False
+    end
+    object edtPublicKey: TEdit
+      Left = 8
+      Height = 23
+      Top = 74
+      Width = 360
+      TabOrder = 1
+    end
+    object edtOpFee: TEdit
+      Left = 8
+      Height = 23
+      Top = 144
+      Width = 360
+      TabOrder = 2
+    end
+    object lblOpFee: TLabel
+      Left = 8
+      Height = 15
+      Top = 112
+      Width = 74
+      Caption = 'Operation Fee'
+      ParentColor = False
+    end
+  end
+  object lblTotalBalances: TLabel
+    Left = 24
+    Height = 15
+    Top = 16
+    Width = 176
+    Caption = 'Selected Accounts Total Balance: '
+    ParentColor = False
+  end
+  object lblTotalBalanceValue: TLabel
+    Left = 208
+    Height = 15
+    Top = 16
+    Width = 70
+    Caption = 'Total Balance'
+    Font.Color = clGreen
+    ParentColor = False
+    ParentFont = False
+  end
+end

+ 151 - 0
src/gui/wizards/UWIZTransferAccount_Transaction.pas

@@ -0,0 +1,151 @@
+unit UWIZTransferAccount_Transaction;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UCommon, UCommon.Collections, UWallet,
+  UFRMAccountSelect, UNode, UWizard, UWIZTransferAccount, UWIZTransferAccount_TransactionPayload,
+  UWIZTransferAccount_Confirmation;
+
+type
+
+  { TWIZTransferAccount_Transaction }
+
+  TWIZTransferAccount_Transaction = class(TWizardForm<TWIZTransferAccountModel>)
+    cbSignerAccount: TComboBox;
+    edtOpFee: TEdit;
+    edtPublicKey: TEdit;
+    gbTransaction: TGroupBox;
+    lblOpFee: TLabel;
+    lblpublickey: TLabel;
+    lblTotalBalanceValue: TLabel;
+    lblTotalBalances: TLabel;
+    lblBalance: TLabel;
+    procedure cbSignerAccountChange(Sender: TObject);
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UUserInterface, USettings;
+
+{ TWIZTransferAccount_Transaction }
+
+procedure TWIZTransferAccount_Transaction.cbSignerAccountChange(Sender: TObject);
+begin
+  if cbSignerAccount.ItemIndex < 1 then
+  begin
+    lblBalance.Font.Color := clRed;
+    lblBalance.Caption := 'Please Select Signer Account';
+  end
+  else
+  begin
+    lblBalance.Font.Color := clGreen;
+    lblBalance.Caption := Format('%s PASC',
+      [TAccountComp.FormatMoney(Model.SelectedAccounts[PtrInt(
+      cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])].Balance)]);
+  end;
+end;
+
+procedure TWIZTransferAccount_Transaction.OnPresent;
+
+  function GetAccNoWithChecksum(AAccountNumber: cardinal): string;
+  begin
+    Result := TAccountComp.AccountNumberToAccountTxtNumber(AAccountNumber);
+  end;
+
+var
+  acc: TAccount;
+  accNumberwithChecksum: string;
+  totalBalance: int64;
+  i: integer;
+begin
+  cbSignerAccount.Items.BeginUpdate;
+  totalBalance := 0;
+  try
+    cbSignerAccount.Items.Clear;
+    cbSignerAccount.Items.Add('Select Signer Account');
+    for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+    begin
+      acc := Model.SelectedAccounts[i];
+      accNumberwithChecksum := GetAccNoWithChecksum(acc.account);
+      totalBalance := totalBalance + acc.balance;
+      cbSignerAccount.Items.AddObject(accNumberwithChecksum, TObject(i));
+    end;
+  finally
+    cbSignerAccount.Items.EndUpdate;
+  end;
+  cbSignerAccount.ItemIndex := Model.SelectedIndex;
+  cbSignerAccountChange(Self);
+  lblTotalBalanceValue.Caption :=
+    Format('%s PASC', [TAccountComp.FormatMoney(totalBalance)]);
+
+  edtOpFee.Text := TAccountComp.FormatMoney(TSettings.DefaultFee);
+end;
+
+procedure TWIZTransferAccount_Transaction.OnNext;
+begin
+  Model.SelectedIndex := cbSignerAccount.ItemIndex;
+  Model.SignerAccount := Model.SelectedAccounts[PtrInt(
+    cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])];
+  Model.NewPublicKey := Trim(edtPublicKey.Text);
+  // make a deep copy
+  Model.SortedAccounts := Copy(Model.SelectedAccounts);
+  // must ensure that Signer account is last in the new array according version 2 protocol
+  TArrayTool<TAccount>.MoveItem(Model.SortedAccounts,
+    TArrayTool<TAccount>.IndexOf(Model.SortedAccounts, Model.SignerAccount),
+    High(Model.SortedAccounts));
+  UpdatePath(ptReplaceAllNext, [TWIZTransferAccount_TransactionPayload,
+    TWIZTransferAccount_Confirmation]);
+end;
+
+function TWIZTransferAccount_Transaction.Validate(out message: ansistring): boolean;
+var
+  i: integer;
+begin
+  if cbSignerAccount.ItemIndex < 1 then
+  begin
+    message := 'A signer account must be selected';
+    Result := False;
+    Exit;
+  end;
+
+  if not TAccountComp.TxtToMoney(Trim(edtOpFee.Text), Model.DefaultFee) then
+  begin
+    message := 'Invalid fee value "' + edtOpFee.Text + '"';
+    Result := False;
+    Exit;
+  end;
+
+  Result := TAccountComp.AccountKeyFromImport(edtPublicKey.Text,
+    Model.AccountKey, message);
+  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+  begin
+    if TAccountComp.EqualAccountKeys(Model.SelectedAccounts[i].accountInfo.accountKey,
+      Model.AccountKey) then
+    begin
+      Result := False;
+      message := 'new public key is same as selected account public key';
+    end;
+  end;
+end;
+
+end.

+ 98 - 0
src/gui/wizards/UWIZTransferAccount_TransactionPayload.lfm

@@ -0,0 +1,98 @@
+object WIZTransferAccount_TransactionPayload: TWIZTransferAccount_TransactionPayload
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = mmoPayload
+  Caption = 'Form1'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.1.0'
+  Visible = False
+  object grpPayload: TGroupBox
+    Left = 8
+    Height = 244
+    Top = 2
+    Width = 416
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    Caption = 'Transfer Transaction Payload'
+    ClientHeight = 224
+    ClientWidth = 412
+    TabOrder = 0
+    object paPayload: TPanel
+      Left = 8
+      Height = 214
+      Top = 2
+      Width = 396
+      Anchors = [akTop, akLeft, akRight, akBottom]
+      BevelOuter = bvNone
+      ClientHeight = 214
+      ClientWidth = 396
+      TabOrder = 0
+      object mmoPayload: TMemo
+        Left = 0
+        Height = 70
+        Top = 136
+        Width = 386
+        TabOrder = 0
+      end
+      object Label1: TLabel
+        Left = 0
+        Height = 15
+        Top = 118
+        Width = 69
+        Caption = 'Payload Data'
+        ParentColor = False
+      end
+      object rbEncryptedWithOldEC: TRadioButton
+        Left = 3
+        Height = 19
+        Top = 0
+        Width = 176
+        Caption = 'Encrypted with old public key'
+        TabOrder = 1
+      end
+      object rbEncryptedWithEC: TRadioButton
+        Left = 3
+        Height = 19
+        Top = 24
+        Width = 227
+        Caption = 'Encrypted with dest account public key'
+        Checked = True
+        TabOrder = 2
+        TabStop = True
+      end
+      object rbEncryptedWithPassword: TRadioButton
+        Left = 3
+        Height = 19
+        Top = 48
+        Width = 152
+        Caption = 'Encrypted with password'
+        TabOrder = 3
+      end
+      object lblPassword: TLabel
+        Left = 3
+        Height = 15
+        Top = 73
+        Width = 53
+        Caption = 'Password:'
+        ParentColor = False
+      end
+      object rbNotEncrypted: TRadioButton
+        Left = 3
+        Height = 19
+        Top = 94
+        Width = 181
+        Caption = 'Don''t encrypt (public payload)'
+        TabOrder = 4
+      end
+      object edtPassword: TEdit
+        Left = 64
+        Height = 23
+        Top = 70
+        Width = 160
+        TabOrder = 5
+      end
+    end
+  end
+end

+ 84 - 0
src/gui/wizards/UWIZTransferAccount_TransactionPayload.pas

@@ -0,0 +1,84 @@
+unit UWIZTransferAccount_TransactionPayload;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UCommon, UCommon.Collections,
+  UWizard, UWIZTransferAccount;
+
+type
+
+  { TWIZTransferAccount_TransactionPayload }
+
+  TWIZTransferAccount_TransactionPayload = class(TWizardForm<TWIZTransferAccountModel>)
+    edtPassword: TEdit;
+    grpPayload: TGroupBox;
+    Label1: TLabel;
+    lblPassword: TLabel;
+    mmoPayload: TMemo;
+    paPayload: TPanel;
+    rbEncryptedWithOldEC: TRadioButton;
+    rbEncryptedWithEC: TRadioButton;
+    rbEncryptedWithPassword: TRadioButton;
+    rbNotEncrypted: TRadioButton;
+  public
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UUserInterface;
+
+{ TWIZTransferAccount_TransactionPayload }
+
+procedure TWIZTransferAccount_TransactionPayload.OnNext;
+begin
+  Model.Payload := mmoPayload.Lines.Text;
+  if rbEncryptedWithOldEC.Checked then
+  begin
+    Model.PayloadEncryptionMode := akaEncryptWithOldEC;
+  end
+  else
+  if rbEncryptedWithEC.Checked then
+  begin
+    Model.PayloadEncryptionMode := akaEncryptWithEC;
+  end
+  else
+  if rbEncryptedWithPassword.Checked then
+  begin
+    Model.PayloadEncryptionMode := akaEncryptWithPassword;
+  end
+  else
+  if rbNotEncrypted.Checked then
+  begin
+    Model.PayloadEncryptionMode := akaNotEncrypt;
+  end;
+end;
+
+function TWIZTransferAccount_TransactionPayload.Validate(out message: ansistring): boolean;
+begin
+  if (not rbNotEncrypted.Checked) and (not rbEncryptedWithEC.Checked) and
+    (not rbEncryptedWithOldEC.Checked) and (not rbEncryptedWithPassword.Checked) then
+  begin
+    message := 'you must select an encryption option for payload';
+    Result := False;
+    Exit;
+  end;
+end;
+
+end.

+ 33 - 1
src/pascalcoin_wallet.lpi

@@ -33,7 +33,7 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item1>
       </Item1>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="78">
+    <Units Count="83">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -435,6 +435,38 @@
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit77>
       </Unit77>
+      <Unit78>
+        <Filename Value="gui\wizards\UWIZTransferAccount.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit78>
+      <Unit79>
+        <Filename Value="gui\wizards\UWIZTransferAccount_Start.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZTransferAccount_Start"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit79>
+      <Unit80>
+        <Filename Value="gui\wizards\UWIZTransferAccount_Transaction.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZTransferAccount_Transaction"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit80>
+      <Unit81>
+        <Filename Value="gui\wizards\UWIZTransferAccount_Confirmation.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZTransferAccount_Confirmation"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit81>
+      <Unit82>
+        <Filename Value="gui\wizards\UWIZTransferAccount_TransactionPayload.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZTransferAccount_TransactionPayload"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit82>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>