Bläddra i källkod

first commit of PASC Sending Wizard.

Ugochukwu Mmaduekwe 7 år sedan
förälder
incheckning
9f0b8f5ab5

+ 1 - 1
src/gui/UCTRLWallet.lfm

@@ -10,7 +10,7 @@ object CTRLWallet: TCTRLWallet
   ClientWidth = 1151
   OnCreate = FormCreate
   OnResize = FormResize
-  LCLVersion = '1.8.2.0'
+  LCLVersion = '1.8.1.0'
   Visible = False
   object PairSplitter1: TPairSplitter
     Left = 0

+ 193 - 96
src/gui/UCTRLWallet.pas

@@ -9,7 +9,7 @@ interface
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
   ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI,
-  UAccounts, UDataSources, UNode;
+  UAccounts, UDataSources, UNode, UWIZSendPASC;
 
 type
 
@@ -53,14 +53,14 @@ type
     procedure miSendPASCClick(Sender: TObject);
     procedure miTransferAccountsClick(Sender: TObject);
   private
-    FNodeNotifyEvents : TNodeNotifyEvents;
-    FAccountsMode : TCTRLWalletAccountsMode;
-    FOperationsMode : TCTRLWalletOperationsMode;
-    FOperationsHistory : TCTRLWalletOperationsHistory;
-    FAccountsGrid : TVisualGrid;
-    FOperationsGrid : TVisualGrid;
-    FAccountsDataSource : TUserAccountsDataSource;
-    FOperationsDataSource : TAccountsOperationsDataSource;
+    FNodeNotifyEvents: TNodeNotifyEvents;
+    FAccountsMode: TCTRLWalletAccountsMode;
+    FOperationsMode: TCTRLWalletOperationsMode;
+    FOperationsHistory: TCTRLWalletOperationsHistory;
+    FAccountsGrid: TVisualGrid;
+    FOperationsGrid: TVisualGrid;
+    FAccountsDataSource: TUserAccountsDataSource;
+    FOperationsDataSource: TAccountsOperationsDataSource;
     procedure SetAccountsMode(AMode: TCTRLWalletAccountsMode);
     procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
     procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
@@ -69,15 +69,23 @@ type
     procedure OnNodeBlocksChanged(Sender: TObject);
     procedure OnNodeNewOperation(Sender: TObject);
     procedure OnAccountsUpdated(Sender: TObject);
-    procedure OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnAccountsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
-    procedure OnOperationsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
-    procedure OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+    procedure OnAccountsSelected(Sender: TObject;
+      constref ASelection: TVisualGridSelection);
+    procedure OnOperationSelected(Sender: TObject;
+      constref ASelection: TVisualGridSelection);
+    procedure OnAccountsGridColumnInitialize(Sender: TObject;
+      AColIndex: integer; AColumn: TVisualColumn);
+    procedure OnOperationsGridColumnInitialize(Sender: TObject;
+      AColIndex: integer; AColumn: TVisualColumn);
+    procedure OnPrepareAccountPopupMenu(Sender: TObject;
+      constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
   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;
 
 implementation
@@ -91,44 +99,45 @@ uses
 { TCTRLWallet }
 
 procedure TCTRLWallet.FormCreate(Sender: TObject);
-var cmbDuration : TComboBox;
+var
+  cmbDuration: TComboBox;
 begin
   // event registrations
-  FNodeNotifyEvents := TNodeNotifyEvents.Create (self);
+  FNodeNotifyEvents := TNodeNotifyEvents.Create(self);
   FNodeNotifyEvents.OnBlocksChanged := OnNodeBlocksChanged;
   FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
 
   // data sources
   FAccountsDataSource := TUserAccountsDataSource.Create(Self);
-  FOperationsDataSource:= TAccountsOperationsDataSource.Create(Self);
+  FOperationsDataSource := TAccountsOperationsDataSource.Create(Self);
 
   // grids
   FAccountsGrid := TVisualGrid.Create(Self);
   FAccountsGrid.SortMode := smMultiColumn;
-  FAccountsGrid.FetchDataInThread:= true;
-  FAccountsGrid.AutoPageSize:= true;
-  FAccountsGrid.SelectionType:= stMultiRow;
-  FAccountsGrid.DeselectionType:= dtDefault;
+  FAccountsGrid.FetchDataInThread := True;
+  FAccountsGrid.AutoPageSize := True;
+  FAccountsGrid.SelectionType := stMultiRow;
+  FAccountsGrid.DeselectionType := dtDefault;
   FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone];
-  FAccountsGrid.DefaultColumnWidths := TArray<Integer>.Create(
-    100,                   // Account
+  FAccountsGrid.DefaultColumnWidths :=
+    TArray<integer>.Create(100,                   // Account
     CT_VISUALGRID_STRETCH, // Name
     100                    // Balance
-  );
-  FAccountsGrid.OnColumnInitialize:= OnAccountsGridColumnInitialize;
+    );
+  FAccountsGrid.OnColumnInitialize := OnAccountsGridColumnInitialize;
   FAccountsGrid.OnSelection := OnAccountsSelected;
   FAccountsGrid.OnFinishedUpdating := OnAccountsUpdated;
-  FAccountsGrid.OnPreparePopupMenu:= OnPrepareAccountPopupMenu;
+  FAccountsGrid.OnPreparePopupMenu := OnPrepareAccountPopupMenu;
 
   FOperationsGrid := TVisualGrid.Create(Self);
   FOperationsGrid.SortMode := smMultiColumn;
-  FOperationsGrid.FetchDataInThread:= true;
-  FOperationsGrid.AutoPageSize:= true;
-  FOperationsGrid.SelectionType:= stRow;
-  FOperationsGrid.DeselectionType:= dtDefault;
+  FOperationsGrid.FetchDataInThread := True;
+  FOperationsGrid.AutoPageSize := True;
+  FOperationsGrid.SelectionType := stRow;
+  FOperationsGrid.DeselectionType := dtDefault;
   FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone];
-  FOperationsGrid.DefaultColumnWidths := TArray<Integer>.Create(
-    130,                   // Time
+  FOperationsGrid.DefaultColumnWidths :=
+    TArray<integer>.Create(130,                   // Time
     CT_VISUALGRID_DEFAULT, // Block
     100,                   // Account
     150,                   // Type
@@ -138,13 +147,13 @@ begin
     CT_VISUALGRID_DEFAULT, // Payload
     80,                    // OPHASH
     CT_VISUALGRID_STRETCH  // Description (stretch)
-  );
-  FOperationsGrid.OnColumnInitialize:= OnOperationsGridColumnInitialize;
+    );
+  FOperationsGrid.OnColumnInitialize := OnOperationsGridColumnInitialize;
   FOperationsGrid.OnSelection := OnOperationSelected;
   FOperationsGrid.PopupMenu := mnuOperationsPopup;
-  FOperationsGrid.Caption.Alignment:= taCenter;
+  FOperationsGrid.Caption.Alignment := taCenter;
   FOperationsGrid.Caption.Text := 'All Account Operations';
-  FOperationsGrid.Caption.Visible := true;
+  FOperationsGrid.Caption.Visible := True;
 
   cmbDuration := TComboBox.Create(FOperationsGrid);
   FOperationsGrid.WidgetControl := cmbDuration;
@@ -154,16 +163,17 @@ begin
     cmbDuration.AddItem('Maximum', TObject(wohFullHistory));
   finally
     cmbDuration.Items.EndUpdate;
-    cmbDuration.ItemIndex:=0;;
+    cmbDuration.ItemIndex := 0;
+    ;
   end;
-  cmbDuration.OnChange:=cmbDurationChange;
+  cmbDuration.OnChange := cmbDurationChange;
 
   // dock operations grid in panel
   paOperations.AddControlDockCenter(FOperationsGrid);
 
   // Configure grid states
   AccountsMode := wamMyAccounts;
-  OperationsMode:= womAllAccounts;
+  OperationsMode := womAllAccounts;
   OperationsHistory := woh30Days;
 end;
 
@@ -179,62 +189,73 @@ begin
 
 end;
 
-procedure TCTRLWallet.OnAccountsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
+procedure TCTRLWallet.OnAccountsGridColumnInitialize(Sender: TObject;
+  AColIndex: integer; AColumn: TVisualColumn);
 begin
   case AColIndex of
-     2: AColumn.InternalColumn.Alignment := taRightJustify;
+    2: AColumn.InternalColumn.Alignment := taRightJustify;
   end;
 end;
 
-procedure TCTRLWallet.OnOperationsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
+procedure TCTRLWallet.OnOperationsGridColumnInitialize(Sender: TObject;
+  AColIndex: integer; AColumn: TVisualColumn);
 begin
   case AColIndex of
-     4, 5, 6: AColumn.InternalColumn.Alignment := taRightJustify;
+    4, 5, 6: AColumn.InternalColumn.Alignment := taRightJustify;
   end;
 end;
 
 procedure TCTRLWallet.SetAccountsMode(AMode: TCTRLWalletAccountsMode);
 begin
-  paAccounts.RemoveAllControls(false);
+  paAccounts.RemoveAllControls(False);
   case AMode of
-     wamMyAccounts: begin
-       FOperationsGrid.DataSource := FOperationsDataSource;
-       FAccountsGrid.DataSource := FAccountsDataSource;
-       FAccountsGrid.Caption.Text := 'My Accounts';
-       paAccounts.AddControlDockCenter(FAccountsGrid);
-       FAccountsGrid.RefreshGrid;
-     end;
-     wamFirstAccount: raise Exception.Create('Not implemented');
+    wamMyAccounts:
+    begin
+      FOperationsGrid.DataSource := FOperationsDataSource;
+      FAccountsGrid.DataSource := FAccountsDataSource;
+      FAccountsGrid.Caption.Text := 'My Accounts';
+      paAccounts.AddControlDockCenter(FAccountsGrid);
+      FAccountsGrid.RefreshGrid;
+    end;
+    wamFirstAccount: raise Exception.Create('Not implemented');
   end;
 end;
 
 procedure TCTRLWallet.SetOperationsMode(AMode: TCTRLWalletOperationsMode);
 
-  function GetAccNo (constref AAccount : TAccount) : Cardinal; overload;
+  function GetAccNo(constref AAccount: TAccount): cardinal; overload;
   begin
     Result := AAccount.account;
   end;
 
-  function GetAccNo(constref ARow : Variant) : Cardinal; overload;
+  function GetAccNo(constref ARow: variant): cardinal; overload;
   begin
-    if NOT TAccountComp.AccountTxtNumberToAccountNumber( ARow.Account, Result ) then
-      raise Exception.Create('Internal Error: Unable to parse account number from table row');
+    if not TAccountComp.AccountTxtNumberToAccountNumber(ARow.Account, Result) then
+      raise Exception.Create(
+        'Internal Error: Unable to parse account number from table row');
   end;
 
 begin
   case AMode of
-     womAllAccounts: begin
-       FOperationsGrid.Caption.Text := 'All Accounts';
-       FOperationsDataSource.Accounts := TListTool<TAccount, Cardinal>.Transform( FAccountsDataSource.LastKnownUserAccounts, GetAccNo );
-     end;
-     womSelectedAccounts: begin
-       FOperationsGrid.Caption.Text := 'Selected Accounts';
-       FOperationsDataSource.Accounts := TListTool<Variant, Cardinal>.Transform( FAccountsGrid.SelectedRows, GetAccNo);
-     end
-     else raise ENotSupportedException.Create(Format('AMode %d not supported', [Integer(AMode)]));
+    womAllAccounts:
+    begin
+      FOperationsGrid.Caption.Text := 'All Accounts';
+      FOperationsDataSource.Accounts :=
+        TListTool<TAccount, cardinal>.Transform(
+        FAccountsDataSource.LastKnownUserAccounts, GetAccNo);
+    end;
+    womSelectedAccounts:
+    begin
+      FOperationsGrid.Caption.Text := 'Selected Accounts';
+      FOperationsDataSource.Accounts :=
+        TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNo);
+    end
+    else
+      raise ENotSupportedException.Create(Format('AMode %d not supported',
+        [integer(AMode)]));
   end;
   FOperationsGrid.RefreshGrid;
-  FOperationsMode:=AMode;
+  FOperationsMode := AMode;
 end;
 
 procedure TCTRLWallet.SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
@@ -261,39 +282,48 @@ end;
 
 procedure TCTRLWallet.OnAccountsUpdated(Sender: TObject);
 begin
-   lblTotalPASC.Caption := TAccountComp.FormatMoney( FAccountsDataSource.Overview.TotalPASC );
-   lblTotalPASA.Caption := Format('%d', [FAccountsDataSource.Overview.TotalPASA] );
+  lblTotalPASC.Caption := TAccountComp.FormatMoney(
+    FAccountsDataSource.Overview.TotalPASC);
+  lblTotalPASA.Caption := Format('%d', [FAccountsDataSource.Overview.TotalPASA]);
 end;
 
-procedure TCTRLWallet.OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+procedure TCTRLWallet.OnAccountsSelected(Sender: TObject;
+  constref ASelection: TVisualGridSelection);
 var
-  row : longint;
-  selectedAccounts : Generics.Collections.TList<Cardinal>;
-  acc : Cardinal;
-  GC : TDisposables;
+  row: longint;
+  selectedAccounts: Generics.Collections.TList<cardinal>;
+  acc: cardinal;
+  GC: TDisposables;
 begin
-  selectedAccounts := GC.AddObject( TList<Cardinal>.Create ) as TList<Cardinal>;
+  selectedAccounts := GC.AddObject(TList<cardinal>.Create) as TList<cardinal>;
 
-  if ASelection.RowCount > 0 then begin
-    for row := ASelection.Row to (ASelection.Row + ASelection.RowCount - 1) do begin
-      if (TAccountComp.AccountTxtNumberToAccountNumber( FAccountsGrid.Rows[row].Account, acc)) then
+  if ASelection.RowCount > 0 then
+  begin
+    for row := ASelection.Row to (ASelection.Row + ASelection.RowCount - 1) do
+    begin
+      if (TAccountComp.AccountTxtNumberToAccountNumber(
+        FAccountsGrid.Rows[row].Account, acc)) then
         selectedAccounts.Add(acc);
     end;
     FOperationsDataSource.Accounts := selectedAccounts.ToArray;
     FOperationsGrid.RefreshGrid;
-  end else begin
-    OperationsMode:= womAllAccounts;
+  end
+  else
+  begin
+    OperationsMode := womAllAccounts;
   end;
 end;
 
-procedure TCTRLWallet.OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+procedure TCTRLWallet.OnOperationSelected(Sender: TObject;
+  constref ASelection: TVisualGridSelection);
 var
-  row : longint;
-  v : Variant;
-  ophash : AnsiString;
+  row: longint;
+  v: variant;
+  ophash: ansistring;
 begin
   row := ASelection.Row;
-  if (row >= 0) AND (row < FOperationsGrid.RowCount) then begin
+  if (row >= 0) and (row < FOperationsGrid.RowCount) then
+  begin
     v := FOperationsGrid.Rows[row];
     ophash := FOperationsGrid.Rows[row].OPHASH;
     if TPCOperation.IsValidOperationHash(ophash) then
@@ -308,23 +338,25 @@ end;
 
 procedure TCTRLWallet.cmbDurationChange(Sender: TObject);
 var
-  cmbDuration : TComboBox;
+  cmbDuration: TComboBox;
 begin
   cmbDuration := Sender as TComboBox;
   if not Assigned(cmbDuration) then
     exit;
 
   case cmbDuration.ItemIndex of
-     0: OperationsHistory := woh30Days;
-     1: OperationsHistory := wohFullHistory;
+    0: OperationsHistory := woh30Days;
+    1: OperationsHistory := wohFullHistory;
   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
   miSep1.Visible := ASelection.RowCount = 1;
   miAccountInfo.Visible := ASelection.RowCount = 1;
-  miTransferAccounts.Caption := IIF( ASelection.RowCount = 1, 'Transfer Account', 'Transfer Accounts');
+  miTransferAccounts.Caption :=
+    IIF(ASelection.RowCount = 1, 'Transfer Account', 'Transfer Accounts');
   APopupMenu := mnuAccountsPopup;
 end;
 
@@ -334,8 +366,72 @@ begin
 end;
 
 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
+  Scoped: TDisposables;
+  wiz: TWIZSendPASCWizard;
+  model: TWizSendPASCModel;
+  AccountNumbersWithoutChecksum: TArray<cardinal>;
 begin
-  raise ENotImplemented.Create('Not Implemented');
+  wiz := Scoped.AddObject(TWIZSendPASCWizard.Create(nil)) as TWIZSendPASCWizard;
+  model := Scoped.AddObject(TWizSendPASCModel.Create(nil)) as TWizSendPASCModel;
+
+  AccountNumbersWithoutChecksum :=
+    TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
+    GetAccNoWithoutChecksum);
+
+  model.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
+  model.SelectedIndex := 0;
+  wiz.Start(model);
 end;
 
 procedure TCTRLWallet.miTransferAccountsClick(Sender: TObject);
@@ -350,9 +446,10 @@ end;
 
 procedure TCTRLWallet.miOperationInfoClick(Sender: TObject);
 begin
-  if FOperationsGrid.Selection.RowCount = 0 then exit;
-  TUserInterface.ShowOperationInfoDialog(Self, FOperationsGrid.SelectedRows[0].EntityKey);
+  if FOperationsGrid.Selection.RowCount = 0 then
+    exit;
+  TUserInterface.ShowOperationInfoDialog(Self,
+    FOperationsGrid.SelectedRows[0].EntityKey);
 end;
 
 end.
-

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

@@ -0,0 +1,76 @@
+unit UWIZSendPASC;
+
+{$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, UWizard, UAccounts;
+
+type
+
+  { TWIZSendPASCModel }
+  TWIZSendPASCModel = class(TComponent)
+    public
+      SelectedIndex: Integer;
+      SelectedAccounts: TArray<TAccount>;
+      SignerAccount: TAccount;
+  end;
+
+  { TWIZSendPASCWizard }
+
+  TWIZSendPASCWizard = class(TWizard<TWIZSendPASCModel>)
+    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
+  UCrypto,
+  UWallet,
+  UWIZSendPASC_Start,
+  UWIZSendPASC_Transaction,
+  UWIZSendPASC_Confirmation,
+  UWIZSendPASC_Completion;
+
+constructor TWIZSendPASCWizard.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner, [TWIZSendPASC_Start, TWIZSendPASC_Completion]);
+  TitleText := 'Send PASC';
+  FinishText := 'Send PASC';
+end;
+
+function TWIZSendPASCWizard.DetermineHasNext : boolean;
+begin
+  Result := NOT (CurrentScreen is TWIZSendPASC_Completion);
+end;
+
+function TWIZSendPASCWizard.DetermineHasPrevious : boolean;
+begin
+  Result := inherited DetermineHasPrevious;
+end;
+
+function TWIZSendPASCWizard.FinishRequested(out message : AnsiString) : boolean;
+begin
+  // Execute the PASC Sending here
+    raise ENotImplemented.Create('Operation Not Yet Implemented');
+end;
+
+function TWIZSendPASCWizard.CancelRequested(out message : AnsiString) : boolean;
+begin
+  Result := true;
+end;
+
+end.
+

+ 18 - 0
src/gui/wizards/UWIZSendPASC_Completion.lfm

@@ -0,0 +1,18 @@
+object WIZSendPASC_Completion: TWIZSendPASC_Completion
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZSendPASC_Completion'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object Button1: TButton
+    Left = 203
+    Height = 25
+    Top = 153
+    Width = 75
+    Caption = 'Button1'
+    TabOrder = 0
+  end
+end

+ 49 - 0
src/gui/wizards/UWIZSendPASC_Completion.pas

@@ -0,0 +1,49 @@
+unit UWIZSendPASC_Completion;
+
+{$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,
+  UWizard, UWIZSendPASC;
+
+type
+
+  { TWIZSendPASC_Completion }
+
+  TWIZSendPASC_Completion = class(TWizardForm<TWIZSendPASCModel>)
+    Button1: TButton;
+
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+{ TWIZSendPASC_Completion }
+
+procedure TWIZSendPASC_Completion.OnPresent;
+begin
+  inherited OnPresent;
+end;
+
+procedure TWIZSendPASC_Completion.OnNext;
+begin
+  inherited OnNext;
+end;
+
+end.
+

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

@@ -0,0 +1,18 @@
+object WIZSendPASC_Confirmation: TWIZSendPASC_Confirmation
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZSendPASC_Confirmation'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object Edit1: TEdit
+    Left = 144
+    Height = 23
+    Top = 148
+    Width = 80
+    TabOrder = 0
+    Text = 'Edit1'
+  end
+end

+ 48 - 0
src/gui/wizards/UWIZSendPASC_Confirmation.pas

@@ -0,0 +1,48 @@
+unit UWIZSendPASC_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,
+  UWizard, UWIZSendPASC;
+
+type
+
+  { TWIZSendPASC_Confirmation }
+
+  TWIZSendPASC_Confirmation = class(TWizardForm<TWIZSendPASCModel>)
+    Edit1: TEdit;
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+{ TWIZSendPASC_Confirmation }
+
+procedure TWIZSendPASC_Confirmation.OnPresent;
+begin
+  inherited OnPresent;
+end;
+
+procedure TWIZSendPASC_Confirmation.OnNext;
+begin
+  inherited OnNext;
+end;
+
+end.
+

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

@@ -0,0 +1,33 @@
+object WIZSendPASC_Start: TWIZSendPASC_Start
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = txtSelectedAccountNumbersAndBalances
+  Caption = 'WIZSendPASC_Start'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.1.0'
+  Visible = False
+  object Label1: TLabel
+    Left = 96
+    Height = 32
+    Top = 16
+    Width = 479
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'List of Selected Accounts and Balances'
+    ParentColor = False
+    WordWrap = True
+  end
+  object txtSelectedAccountNumbersAndBalances: TMemo
+    Left = 24
+    Height = 160
+    Top = 56
+    Width = 379
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    ReadOnly = True
+    ScrollBars = ssBoth
+    TabOrder = 0
+  end
+end

+ 63 - 0
src/gui/wizards/UWIZSendPASC_Start.pas

@@ -0,0 +1,63 @@
+unit UWIZSendPASC_Start;
+
+{$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, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  UWizard, UWIZSendPASC, UWIZSendPASC_Transaction, UWIZSendPASC_Completion;
+
+type
+
+  { TWIZSendPASC_Start }
+
+  TWIZSendPASC_Start = class(TWizardForm<TWIZSendPASCModel>)
+    Label1: TLabel;
+    txtSelectedAccountNumbersAndBalances: TMemo;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts;
+
+{ TWIZSendPASC_Start }
+
+
+procedure TWIZSendPASC_Start.OnPresent;
+
+function GetAccNoWithChecksum(const AAccountNumber: Cardinal): String;
+begin
+  result := TAccountComp.AccountNumberToAccountTxtNumber(AAccountNumber);
+end;
+var
+  acc: TAccount;
+  i: Integer;
+begin
+  txtSelectedAccountNumbersAndBalances.Clear;
+  for i := 0 to High(Model.SelectedAccounts) do
+  begin
+    acc := Model.SelectedAccounts[i];
+    txtSelectedAccountNumbersAndBalances.Append(Format('This Account %s has %s PASC', [GetAccNoWithChecksum(acc.Account), TAccountComp.FormatMoney(acc.balance)]));
+  end;
+end;
+
+procedure TWIZSendPASC_Start.OnNext;
+begin
+  UpdatePath(ptReplaceAllNext, [TWIZSendPASC_Transaction, TWIZSendPASC_Completion]);
+end;
+
+end.
+

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

@@ -0,0 +1,150 @@
+object WIZSendPASC_Transaction: TWIZSendPASC_Transaction
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = cbSignerAccount
+  Caption = 'WIZSendPASC_Transaction'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object gbTransaction: TGroupBox
+    Left = 22
+    Height = 192
+    Top = 40
+    Width = 384
+    Caption = '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 lblDestAcc: TLabel
+      Left = 8
+      Height = 15
+      Top = 48
+      Width = 108
+      Caption = 'Destination Account'
+      ParentColor = False
+    end
+    object edtDestAcc: TEdit
+      Left = 8
+      Height = 23
+      Top = 74
+      Width = 136
+      TabOrder = 1
+    end
+    object lblAmount: TLabel
+      Left = 8
+      Height = 15
+      Top = 116
+      Width = 44
+      Caption = 'Amount'
+      ParentColor = False
+    end
+    object edtAmt: TEdit
+      Left = 8
+      Height = 23
+      Top = 143
+      Width = 136
+      TabOrder = 2
+    end
+    object btnSearch: TSpeedButton
+      Left = 152
+      Height = 22
+      Top = 75
+      Width = 23
+      Glyph.Data = {
+        36040000424D3604000000000000360000002800000010000000100000000100
+        2000000000000004000064000000640000000000000000000000000000000000
+        0000000000000000000F00000010000000100000001000000010000000100000
+        001000000010000000100000000F000000000000000000000000000000003509
+        033190370DEBA6410FFFA6410FFFA6410FFFA6410FFFA6410FFFA6410FFFA641
+        0FFFA6410FFFA6410FFFA6410FFF90370DEB350903310000000000000000953A
+        0EE6B14B10FFB04B10FFB04B10FFB04B10FFB04B10FFB04B10FFB04B10FFB04B
+        10FFB14B11FFAE460CFFB14B11FFB14B10FF953A0EE60000000000000001AA47
+        12FFB24D11FFB24D11FFB24D11FFB24D11FFB34E12FFB34E12FFB24D11FFB34E
+        12FFAB440DFFE1C19FFFAC4914FFB34E12FFAA4712FF0000000100000001AD4A
+        13FFB65113FFB65113FFB55113FFB14A0EFFAA3F05FFAA3F05FFB14A0EFFAE48
+        0EFFEEDCBCFFFFFFE2FFE6C6A1FFB44E0FFFAD4A13FF0000000100000001AF4D
+        14FFB85414FFB85414FFB75A25FFE5C8A7FFFFFFEBFFFFFFEAFFE3C3A1FFECD7
+        B8FFFFFFE4FFF1DFBEFFB55011FFB85414FFAF4D14FF0000000100000001B251
+        15FFBB5816FFBB6027FFFFFFEAFFEBCFABFFCC814BFFCC824CFFECD1AEFFFFFF
+        E8FFEFDAB9FFB95412FFBB5816FFBB5816FFB25115FF0000000100000001B555
+        16FFBC5712FFEACDAAFFEBCEAAFFBB540EFFBF5E19FFBF5E19FFBB550FFFEDD2
+        B0FFE7C7A5FFBC5712FFBE5C16FFBE5C16FFB55516FF0000000100000001B859
+        19FFBD5915FFFFFFFCFFD08857FFC56B29FFC46B29FFC46A29FFC56B29FFD18B
+        5BFFFFFFF9FFBF5D1BFFC46A27FFC36623FFB85919FF0000000100000001C170
+        35FFC66B2BFFFFFFFFFFD38F64FFCB7839FFCA7739FFCA7739FFCB7839FFD492
+        67FFFFFFFFFFC66C2CFFCA7739FFCB7739FFC17035FF0000000100000001C77F
+        46FFCF8248FFF1DBCCFFEED3C5FFCC7A40FFD1864CFFD1864CFFCC7A40FFEFD5
+        C8FFF1D9C9FFCF8348FFD0864CFFD0864CFFC77F46FF0000000100000001CD8D
+        59FFD79561FFDA9D6EFFFFFFFFFFF0D7C8FFDA9F79FFDAA079FFF0D8CAFFFFFF
+        FFFFD99C6DFFD79561FFD69460FFD69460FFCD8D59FF0000000100000000D29A
+        6CFFDCA373FFDCA373FFDEA97FFFF5E5D8FFFFFFFFFFFFFFFFFFF5E5D7FFDEA9
+        7EFFDCA373FFDCA373FFDCA373FFDCA373FFD29A6CFF0000000000000000C99C
+        75E0E1AE83FFE1AE84FFE1AE84FFE0AC80FFDFA87AFFDEA87AFFE0AC80FFE1AE
+        84FFE1AE84FFE1AE84FFE1AE84FFE1AE83FFC99C75E000000000FFFFFE007960
+        4721D0AA87DCDCB58FFFDDB590FFDDB590FFDDB590FFDDB590FFDDB590FFDDB5
+        90FFDDB590FFDDB590FFDCB58FFFD0AA87DC79604821FFFFFA0000000000FFFF
+        FF00000000000000000000000000000000000000000000000000000000000000
+        000000000000000000000000000000000000FFFFFF0000000000
+      }
+      OnClick = btnSearchClick
+    end
+    object edtOpFee: TEdit
+      Left = 232
+      Height = 23
+      Top = 144
+      Width = 136
+      TabOrder = 3
+    end
+    object lblOpFee: TLabel
+      Left = 232
+      Height = 15
+      Top = 116
+      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

+ 225 - 0
src/gui/wizards/UWIZSendPASC_Transaction.pas

@@ -0,0 +1,225 @@
+unit UWIZSendPASC_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, UWIZSendPASC, UWIZSendPASC_Confirmation, UWIZSendPASC_Completion;
+
+type
+
+  { TWIZSendPASC_Transaction }
+
+  TWIZSendPASC_Transaction = class(TWizardForm<TWIZSendPASCModel>)
+    cbSignerAccount: TComboBox;
+    edtOpFee: TEdit;
+    edtAmt: TEdit;
+    edtDestAcc: TEdit;
+    gbTransaction: TGroupBox;
+    lblOpFee: TLabel;
+    lblAmount: TLabel;
+    lblDestAcc: TLabel;
+    lblTotalBalanceValue: TLabel;
+    lblTotalBalances: TLabel;
+    lblBalance: TLabel;
+    btnSearch: TSpeedButton;
+    procedure btnSearchClick(Sender: TObject);
+    procedure cbSignerAccountChange(Sender: TObject);
+
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts;
+
+{ TWIZSendPASC_Transaction }
+
+procedure TWIZSendPASC_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 TWIZSendPASC_Transaction.btnSearchClick(Sender: TObject);
+var
+  F: TFRMAccountSelect;
+  c: cardinal;
+begin
+  F := TFRMAccountSelect.Create(Self);
+  F.Position := poMainFormCenter;
+  try
+    F.Node := TNode.Node;
+    F.WalletKeys := TWallet.Keys;
+    F.Filters := edtDestAcc.Tag;
+    if TAccountComp.AccountTxtNumberToAccountNumber(edtDestAcc.Text, c) then
+      F.DefaultAccount := c;
+    F.AllowSelect := True;
+    if F.ShowModal = mrOk then
+    begin
+      edtDestAcc.Text := TAccountComp.AccountNumberToAccountTxtNumber(F.GetSelected);
+    end;
+  finally
+    F.Free;
+  end;
+end;
+
+procedure TWIZSendPASC_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 := 0 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)]);
+
+  if Length(Model.SelectedAccounts) > 1 then
+  begin
+    edtAmt.Text := 'ALL BALANCE';
+    edtAmt.Enabled := False;
+  end
+  else
+  begin
+    edtAmt.Text := TAccountComp.FormatMoney(0);
+  end;
+  edtOpFee.Text := TAccountComp.FormatMoney(0);
+end;
+
+procedure TWIZSendPASC_Transaction.OnNext;
+begin
+  Model.SelectedIndex := cbSignerAccount.ItemIndex;
+  Model.SignerAccount := Model.SelectedAccounts[PtrInt(cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])];
+  UpdatePath(ptReplaceAllNext, [TWIZSendPASC_Confirmation, TWIZSendPASC_Completion]);
+end;
+
+function TWIZSendPASC_Transaction.Validate(out message: ansistring): boolean;
+
+  function GetAccNoWithChecksum(constref AAccount: TAccount): string;
+  begin
+    Result := TAccountComp.AccountNumberToAccountTxtNumber(AAccount.account);
+  end;
+
+var
+  AccountNumbersWithChecksum: TArray<string>;
+  Accounts: TArray<TAccount>;
+  c: cardinal;
+  DestAccount: TAccount;
+  amount, opfee: int64;
+begin
+  Accounts := Model.SelectedAccounts;
+  Result := True;
+  if cbSignerAccount.ItemIndex < 1 then
+  begin
+    message := 'A signer account must be selected';
+    Result := False;
+    Exit;
+  end;
+
+  if not (TAccountComp.AccountTxtNumberToAccountNumber(edtDestAcc.Text, c)) then
+  begin
+    message := 'Invalid destination account (' + edtDestAcc.Text + ')';
+    Result := False;
+    Exit;
+  end;
+
+  if (c < 0) or (c >= TNode.Node.Bank.AccountsCount) then
+  begin
+    message := 'Invalid destination account (' +
+      TAccountComp.AccountNumberToAccountTxtNumber(c) + ')';
+    Result := False;
+    Exit;
+  end;
+
+  DestAccount := TNode.Node.Operations.SafeBoxTransaction.account(c);
+  if Length(Accounts) = 1 then
+  begin
+    if not TAccountComp.TxtToMoney(edtAmt.Text, amount) then
+    begin
+      message := 'Invalid amount (' + edtAmt.Text + ')';
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  AccountNumbersWithChecksum :=
+    TListTool<TAccount, string>.Transform(Accounts, GetAccNoWithCheckSum);
+
+  if TArrayTool<string>.Contains(AccountNumbersWithChecksum, edtDestAcc.Text) then
+  begin
+    message := 'Sender and destination account are the same';
+    Result := False;
+    Exit;
+  end;
+
+  if not TAccountComp.TxtToMoney(Trim(edtOpFee.Text), opfee) then
+  begin
+    message := 'Invalid fee value "' + edtOpFee.Text + '"';
+    Result := False;
+    Exit;
+  end;
+
+  if Length(Model.SelectedAccounts) = 1 then
+  begin
+    if (Accounts[0].balance < (amount + opfee)) then
+    begin
+      message := 'Insufficient funds';
+      Result := False;
+      Exit;
+    end;
+  end;
+
+end;
+
+end.

+ 30 - 2
src/pascalcoin_wallet.lpi

@@ -33,7 +33,7 @@
         <PackageName Value="LCL"/>
       </Item1>
     </RequiredPackages>
-    <Units Count="70">
+    <Units Count="74">
       <Unit0>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <IsPartOfProject Value="True"/>
@@ -388,9 +388,37 @@
         <IsPartOfProject Value="True"/>
       </Unit68>
       <Unit69>
-        <Filename Value="libraries\sphere10\UAutoScope.pas"/>
+        <Filename Value="gui\wizards\UWIZSendPASC.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit69>
+      <Unit70>
+        <Filename Value="gui\wizards\UWIZSendPASC_Confirmation.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_Confirmation"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit70>
+      <Unit71>
+        <Filename Value="gui\wizards\UWIZSendPASC_Start.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_Start"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit71>
+      <Unit72>
+        <Filename Value="gui\wizards\UWIZSendPASC_Transaction.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_Transaction"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit72>
+      <Unit73>
+        <Filename Value="gui\wizards\UWIZSendPASC_Completion.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_Completion"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit73>
     </Units>
   </ProjectOptions>
   <CompilerOptions>