Browse Source

Merge downstream

Herman Schoenfeld 7 years ago
parent
commit
38af7e2fd4
35 changed files with 2166 additions and 289 deletions
  1. 28 0
      src/core.utils/UCoreUtils.pas
  2. 1 9
      src/gui/UCTRLWallet.lfm
  3. 11 38
      src/gui/UCTRLWallet.pas
  4. 46 23
      src/gui/wizards/UWIZModels.pas
  5. 476 0
      src/gui/wizards/operations/UWIZChangeKey.pas
  6. 50 0
      src/gui/wizards/operations/UWIZChangeKey_ConfirmAccount.lfm
  7. 144 0
      src/gui/wizards/operations/UWIZChangeKey_ConfirmAccount.pas
  8. 48 0
      src/gui/wizards/operations/UWIZChangeKey_Confirmation.lfm
  9. 178 0
      src/gui/wizards/operations/UWIZChangeKey_Confirmation.pas
  10. 53 0
      src/gui/wizards/operations/UWIZChangeKey_EnterKey.lfm
  11. 97 0
      src/gui/wizards/operations/UWIZChangeKey_EnterKey.pas
  12. 65 0
      src/gui/wizards/operations/UWIZChangeKey_SelectKey.lfm
  13. 163 0
      src/gui/wizards/operations/UWIZChangeKey_SelectKey.pas
  14. 63 0
      src/gui/wizards/operations/UWIZChangeKey_SelectOption.lfm
  15. 63 0
      src/gui/wizards/operations/UWIZChangeKey_SelectOption.pas
  16. 453 0
      src/gui/wizards/operations/UWIZConfirmAccount.pas
  17. 1 1
      src/gui/wizards/operations/UWIZEnlistAccountForSale_Start.lfm
  18. 5 5
      src/gui/wizards/operations/UWIZFeeOverride.lfm
  19. 5 7
      src/gui/wizards/operations/UWIZFeeOverride.pas
  20. 2 3
      src/gui/wizards/operations/UWIZPayloadContentOverride.pas
  21. 1 0
      src/gui/wizards/operations/UWIZPayloadOverride.lfm
  22. 3 5
      src/gui/wizards/operations/UWIZPayloadOverride.pas
  23. 1 1
      src/gui/wizards/operations/UWIZPayloadPasswordOverride.lfm
  24. 2 3
      src/gui/wizards/operations/UWIZPayloadPasswordOverride.pas
  25. 7 9
      src/gui/wizards/operations/UWIZSelectSignerOverride.pas
  26. 48 42
      src/gui/wizards/operations/UWIZSendPASC.pas
  27. 1 1
      src/gui/wizards/operations/UWIZSendPASC_ConfirmSender.lfm
  28. 40 24
      src/gui/wizards/operations/UWIZSendPASC_ConfirmSender.pas
  29. 43 39
      src/gui/wizards/operations/UWIZSendPASC_Confirmation.pas
  30. 3 1
      src/gui/wizards/operations/UWIZSendPASC_EnterQuantity.pas
  31. 1 0
      src/gui/wizards/operations/UWIZSendPASC_EnterRecipient.lfm
  32. 1 1
      src/gui/wizards/operations/UWIZSendPASC_EnterRecipient.pas
  33. 0 19
      src/gui/wizards/operations/UWIZSendPASC_FeeOverride.lfm
  34. 2 0
      src/gui/wizards/operations/UWIZTransferAccount.pas
  35. 61 58
      src/pascalcoin_wallet.lpi

+ 28 - 0
src/core.utils/UCoreUtils.pas

@@ -34,6 +34,12 @@ TAccountKeyEqualityComparer = class(TEqualityComparer<TAccountKey>)
     class function CalcHashCode(constref AValue: TAccountKey): UInt32;
     class function CalcHashCode(constref AValue: TAccountKey): UInt32;
 end;
 end;
 
 
+{ TCoreTool }
+
+TCoreTool = class(TObject)
+  class function GetSignerCandidates(ANumOps : Integer; const ACandidates : TArray<TAccount>) : TArray<TAccount>; static;
+  end;
+
 TAccountHelper = record helper for TAccount
 TAccountHelper = record helper for TAccount
   function GetAccountString : AnsiString;
   function GetAccountString : AnsiString;
   function GetInfoText(const ABank : TPCBank) : utf8string;
   function GetInfoText(const ABank : TPCBank) : utf8string;
@@ -53,6 +59,28 @@ implementation
 uses
 uses
   UMemory, UConst;
   UMemory, UConst;
 
 
+{ TCoreTool }
+
+class function TCoreTool.GetSignerCandidates(ANumOps: Integer;
+  const ACandidates: TArray<TAccount>): TArray<TAccount>;
+var
+  i: Integer;
+  Fee: Int64;
+  acc: TAccount;
+begin
+  //make deep copy of accounts!!! Very Important
+  Result := Copy(ACandidates);
+  Fee := ANumOps * CT_MOLINA;
+  for i := High(Result) downto Low(Result) do
+    begin
+      acc := Result[i];
+      if not (acc.Balance >= Fee) then
+      begin
+        TArrayTool<TAccount>.RemoveAt(Result, i);
+      end;
+    end;
+end;
+
 { TAccountKeyComparer }
 { TAccountKeyComparer }
 
 
 function TAccountKeyComparer.Compare(constref ALeft, ARight: T): Integer;
 function TAccountKeyComparer.Compare(constref ALeft, ARight: T): Integer;

+ 1 - 9
src/gui/UCTRLWallet.lfm

@@ -10,7 +10,6 @@ object CTRLWallet: TCTRLWallet
   ClientWidth = 1151
   ClientWidth = 1151
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnResize = FormResize
   OnResize = FormResize
-  LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
   object PairSplitter1: TPairSplitter
   object PairSplitter1: TPairSplitter
     Left = 0
     Left = 0
@@ -168,14 +167,7 @@ object CTRLWallet: TCTRLWallet
     end
     end
     object miChangeKey: TMenuItem
     object miChangeKey: TMenuItem
       Caption = 'Change Key'
       Caption = 'Change Key'
-      object miTransferAccounts: TMenuItem
-        Caption = 'Transfer Account(s)'
-        OnClick = miTransferAccountsClick
-      end
-      object miChangeAccountsPrivateKey: TMenuItem
-        Caption = 'Change Account(s) Private Key'
-        OnClick = miChangeAccountsPrivateKeyClick
-      end
+      OnClick = miChangeKeyClick
     end
     end
     object miAccountsMarket: TMenuItem
     object miAccountsMarket: TMenuItem
       Caption = 'Account Market'
       Caption = 'Account Market'

+ 11 - 38
src/gui/UCTRLWallet.pas

@@ -9,8 +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,
-  UWIZChangeAccountPrivateKey;
+  UAccounts, UDataSources, UNode, UWIZSendPASC, UWIZChangeKey;
 
 
 type
 type
 
 
@@ -33,8 +32,6 @@ type
     miOperationInfo: TMenuItem;
     miOperationInfo: TMenuItem;
     miSendPASC: TMenuItem;
     miSendPASC: TMenuItem;
     miChangeKey: TMenuItem;
     miChangeKey: TMenuItem;
-    miTransferAccounts: TMenuItem;
-    miChangeAccountsPrivateKey: TMenuItem;
     miAccountsMarket: TMenuItem;
     miAccountsMarket: TMenuItem;
     miEnlistAccountsForSale: TMenuItem;
     miEnlistAccountsForSale: TMenuItem;
     miDelistAccountsFromSale: TMenuItem;
     miDelistAccountsFromSale: TMenuItem;
@@ -55,11 +52,10 @@ type
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormResize(Sender: TObject);
     procedure FormResize(Sender: TObject);
     procedure miAccountInfoClick(Sender: TObject);
     procedure miAccountInfoClick(Sender: TObject);
+    procedure miChangeKeyClick(Sender: TObject);
     procedure miCopyOphashClick(Sender: TObject);
     procedure miCopyOphashClick(Sender: TObject);
     procedure miOperationInfoClick(Sender: TObject);
     procedure miOperationInfoClick(Sender: TObject);
     procedure miSendPASCClick(Sender: TObject);
     procedure miSendPASCClick(Sender: TObject);
-    procedure miTransferAccountsClick(Sender: TObject);
-    procedure miChangeAccountsPrivateKeyClick(Sender: TObject);
     procedure miEnlistAccountsForSaleClick(Sender: TObject);
     procedure miEnlistAccountsForSaleClick(Sender: TObject);
     procedure miDelistAccountsFromSaleClick(Sender: TObject);
     procedure miDelistAccountsFromSaleClick(Sender: TObject);
   private
   private
@@ -608,10 +604,8 @@ begin
   miAccountInfo.Visible := ASelection.RowCount = 1;
   miAccountInfo.Visible := ASelection.RowCount = 1;
   miSendPASC.Caption :=
   miSendPASC.Caption :=
     IIF(ASelection.RowCount = 1, 'Send PASC', 'Send All PASC');
     IIF(ASelection.RowCount = 1, 'Send PASC', 'Send All PASC');
-  miTransferAccounts.Caption :=
-    IIF(ASelection.RowCount = 1, 'Transfer Account', 'Transfer All Account');
-  miChangeAccountsPrivateKey.Caption :=
-    IIF(ASelection.RowCount = 1, 'Change Account Private Key', 'Change All Account Private Key');
+   miChangeKey.Caption :=
+    IIF(ASelection.RowCount = 1, 'Change Key', 'Change All Key');
   miEnlistAccountsForSale.Caption :=
   miEnlistAccountsForSale.Caption :=
     IIF(ASelection.RowCount = 1, 'Enlist Account For Sale',
     IIF(ASelection.RowCount = 1, 'Enlist Account For Sale',
     'Enlist All Account For Sale');
     'Enlist All Account For Sale');
@@ -654,46 +648,25 @@ begin
     TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
     TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
     GetAccNoWithoutChecksum);
     GetAccNoWithoutChecksum);
 
 
-  model.SendPASC.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  model.SendPASC.SelectedIndex := 0;
+  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
   wiz.Start(model);
   wiz.Start(model);
 end;
 end;
 
 
-procedure TCTRLWallet.miTransferAccountsClick(Sender: TObject);
+procedure TCTRLWallet.miChangeKeyClick(Sender: TObject);
 var
 var
   Scoped: TDisposables;
   Scoped: TDisposables;
-  wiz: TWIZTransferAccountWizard;
+  wiz: TWIZChangeKeyWizard;
   model: TWIZOperationsModel;
   model: TWIZOperationsModel;
   AccountNumbersWithoutChecksum: TArray<cardinal>;
   AccountNumbersWithoutChecksum: TArray<cardinal>;
 begin
 begin
-  wiz := Scoped.AddObject(TWIZTransferAccountWizard.Create(nil)) as
-    TWIZTransferAccountWizard;
-  model := TWIZOperationsModel.Create(wiz, omtTransferAccount);
+   wiz := Scoped.AddObject(TWIZChangeKeyWizard.Create(nil)) as
+    TWIZChangeKeyWizard;
+  model := TWIZOperationsModel.Create(wiz, omtChangeKey);
   AccountNumbersWithoutChecksum :=
   AccountNumbersWithoutChecksum :=
     TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
     TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
     GetAccNoWithoutChecksum);
     GetAccNoWithoutChecksum);
 
 
-  model.TransferAccount.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  model.TransferAccount.SelectedIndex := 0;
-  wiz.Start(model);
-end;
-
-procedure TCTRLWallet.miChangeAccountsPrivateKeyClick(Sender: TObject);
-var
-  Scoped: TDisposables;
-  wiz: TWIZChangeAccountPrivateKeyWizard;
-  model: TWIZOperationsModel;
-  AccountNumbersWithoutChecksum: TArray<cardinal>;
-begin
-  wiz := Scoped.AddObject(TWIZChangeAccountPrivateKeyWizard.Create(nil)) as TWIZChangeAccountPrivateKeyWizard;
-  model := TWIZOperationsModel.Create(wiz, omtChangeAccountPrivateKey);
-
-  AccountNumbersWithoutChecksum :=
-    TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows,
-    GetAccNoWithoutChecksum);
-
-  model.ChangeAccountPrivateKey.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  model.ChangeAccountPrivateKey.SelectedIndex := 0;
+  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
   wiz.Start(model);
   wiz.Start(model);
 end;
 end;
 
 

+ 46 - 23
src/gui/wizards/UWIZModels.pas

@@ -30,11 +30,12 @@ type
   { TWIZOperationsModel }
   { TWIZOperationsModel }
 
 
   TWIZOperationsModel = class(TComponent)
   TWIZOperationsModel = class(TComponent)
-  public type
+  public
+    type
 
 
     { TModelType }
     { TModelType }
 
 
-    TModelType = (omtSendPasc, omtTransferAccount, omtChangeAccountPrivateKey, omtAddKey);
+    TModelType = (omtAccount, omtSendPasc, omtChangeKey, omtTransferAccount, omtChangeAccountPrivateKey, omtAddKey);
 
 
     { TPayloadEncryptionMode }
     { TPayloadEncryptionMode }
 
 
@@ -44,35 +45,50 @@ type
 
 
     TOperationSigningMode = (akaPrimary, akaSecondary);
     TOperationSigningMode = (akaPrimary, akaSecondary);
 
 
+    { TChangeKeyMode }
+
+    TChangeKeyMode = (akaTransferAccountOwnership, akaChangeAccountPrivateKey);
+
+     { TSendPASCMode }
+
+    TSendPASCMode = (akaAllBalance, akaSpecifiedAmount);
+
+    { TAccountModel }
+
+    TAccountModel = class(TComponent)
+    public
+      SelectedAccounts: TArray<TAccount>;
+    end;
+
     { TSendPASCModel }
     { TSendPASCModel }
 
 
     TSendPASCModel = class(TComponent)
     TSendPASCModel = class(TComponent)
     public
     public
-      SelectedIndex: integer;
       SingleAmountToSend: int64;
       SingleAmountToSend: int64;
       DestinationAccount: TAccount;
       DestinationAccount: TAccount;
-      SelectedAccounts: TArray<TAccount>;
+      SendPASCMode: TSendPASCMode;
+    end;
+
+    { TChangeKeyModel }
+
+    TChangeKeyModel = class(TComponent)
+    public
+      ChangeKeyMode: TChangeKeyMode;
     end;
     end;
 
 
     { TTransferAccountModel }
     { TTransferAccountModel }
 
 
     TTransferAccountModel = class(TComponent)
     TTransferAccountModel = class(TComponent)
     public
     public
-      NewPublicKey : string;
-      SelectedIndex: integer;
       AccountKey: TAccountKey;
       AccountKey: TAccountKey;
-      SelectedAccounts: TArray<TAccount>;
     end;
     end;
 
 
     { TChangeAccountPrivateKeyModel }
     { TChangeAccountPrivateKeyModel }
 
 
     TChangeAccountPrivateKeyModel = class(TComponent)
     TChangeAccountPrivateKeyModel = class(TComponent)
     public
     public
-      NewPublicKey : string;
-      SelectedIndex, PrivateKeySelectedIndex: integer;
+      SelectedIndex: integer;
       NewWalletKey: TWalletKey;
       NewWalletKey: TWalletKey;
-      EncodedPayload: TRawBytes;
-      SelectedAccounts: TArray<TAccount>;
     end;
     end;
 
 
     { TFeeModel }
     { TFeeModel }
@@ -88,6 +104,8 @@ type
     public
     public
       OperationSigningMode: TOperationSigningMode;
       OperationSigningMode: TOperationSigningMode;
       SignerAccount: TAccount;
       SignerAccount: TAccount;
+      SignerCandidates: TArray<TAccount>;
+      SelectedIndex: integer;
     end;
     end;
 
 
     { TPayloadModel }
     { TPayloadModel }
@@ -95,28 +113,32 @@ type
     TPayloadModel = class(TComponent)
     TPayloadModel = class(TComponent)
     public
     public
       HasPayload: boolean;
       HasPayload: boolean;
-      Content, Password : string;
+      Content, Password: string;
       Mode: TPayloadEncryptionMode;
       Mode: TPayloadEncryptionMode;
       EncodedBytes: TRawBytes;
       EncodedBytes: TRawBytes;
     end;
     end;
 
 
   private
   private
     FModelType: TModelType;
     FModelType: TModelType;
-    FSendPASC : TSendPASCModel;
-    FTransferAccount : TTransferAccountModel;
-    FChangeAccountPrivateKey : TChangeAccountPrivateKeyModel;
-    FFee : TFeeModel;
-    FSigner : TSignerModel;
-    FPayload : TPayloadModel;
+    FAccount: TAccountModel;
+    FSendPASC: TSendPASCModel;
+    FChangeKey: TChangeKeyModel;
+    FTransferAccount: TTransferAccountModel;
+    FChangeAccountPrivateKey: TChangeAccountPrivateKeyModel;
+    FFee: TFeeModel;
+    FSigner: TSignerModel;
+    FPayload: TPayloadModel;
   public
   public
     constructor Create(AOwner: TComponent; AType: TModelType); overload;
     constructor Create(AOwner: TComponent; AType: TModelType); overload;
     property ModelType: TModelType read FModelType;
     property ModelType: TModelType read FModelType;
+    property Account: TAccountModel read FAccount;
     property SendPASC: TSendPASCModel read FSendPASC;
     property SendPASC: TSendPASCModel read FSendPASC;
+    property ChangeKey: TChangeKeyModel read FChangeKey;
     property TransferAccount: TTransferAccountModel read FTransferAccount;
     property TransferAccount: TTransferAccountModel read FTransferAccount;
-    property ChangeAccountPrivateKey : TChangeAccountPrivateKeyModel read FChangeAccountPrivateKey;
-    property Fee : TFeeModel read FFee;
-    property Signer : TSignerModel read FSigner;
-    property Payload : TPayloadModel read FPayload;
+    property ChangeAccountPrivateKey: TChangeAccountPrivateKeyModel read FChangeAccountPrivateKey;
+    property Fee: TFeeModel read FFee;
+    property Signer: TSignerModel read FSigner;
+    property Payload: TPayloadModel read FPayload;
   end;
   end;
 
 
 implementation
 implementation
@@ -125,10 +147,11 @@ constructor TWIZOperationsModel.Create(AOwner: TComponent; AType: TWIZOperations
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
   FModelType := AType;
   FModelType := AType;
+  FAccount := TAccountModel.Create(Self);
   FSendPASC := TSendPASCModel.Create(Self);
   FSendPASC := TSendPASCModel.Create(Self);
+  FChangeKey := TChangeKeyModel.Create(Self);
   FTransferAccount := TTransferAccountModel.Create(Self);
   FTransferAccount := TTransferAccountModel.Create(Self);
   FChangeAccountPrivateKey := TChangeAccountPrivateKeyModel.Create(Self);
   FChangeAccountPrivateKey := TChangeAccountPrivateKeyModel.Create(Self);
-  FChangeAccountPrivateKey := TChangeAccountPrivateKeyModel.Create(Self);
   FFee := TFeeModel.Create(Self);
   FFee := TFeeModel.Create(Self);
   FSigner := TSignerModel.Create(Self);
   FSigner := TSignerModel.Create(Self);
   FPayload := TPayloadModel.Create(Self);
   FPayload := TPayloadModel.Create(Self);

+ 476 - 0
src/gui/wizards/operations/UWIZChangeKey.pas

@@ -0,0 +1,476 @@
+unit UWIZChangeKey;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Dialogs, UCrypto, UCommon, UWizard, UAccounts, LCLType, UWIZModels;
+
+type
+
+  { TWIZChangeKeyWizard }
+
+  TWIZChangeKeyWizard = class(TWizard<TWIZOperationsModel>)
+  private
+    function UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
+    function UpdateOperationOptions(var errors: string): boolean;
+    function UpdateOpChangeKey(const TargetAccount: TAccount; var SignerAccount: TAccount; var NewPublicKey: TAccountKey; var errors: ansistring): boolean;
+    procedure WIZChangeKeyOwnership();
+  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,
+  UWIZChangeKey_ConfirmAccount,
+  UWIZChangeKey_Confirmation;
+
+{ TWIZChangeKeyWizard }
+
+function TWIZChangeKeyWizard.UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
+var
+  valid: boolean;
+  payload_encrypted, payload_u: string;
+  account: TAccount;
+  public_key: TAccountKey;
+begin
+  valid := False;
+  payload_encrypted := '';
+  Model.Payload.EncodedBytes := '';
+  errors := 'Unknown error';
+  payload_u := Model.Payload.Content;
+
+  try
+    if (payload_u = '') then
+    begin
+      valid := True;
+      Exit;
+    end;
+    case Model.Payload.Mode of
+
+      akaEncryptWithSender:
+      begin
+        // Use sender
+        errors := 'Error encrypting';
+        account := SenderAccount;
+        payload_encrypted := ECIESEncrypt(account.accountInfo.accountKey, payload_u);
+        valid := payload_encrypted <> '';
+      end;
+
+      akaEncryptWithReceiver:
+      begin
+
+        case Model.ChangeKey.ChangeKeyMode of
+          akaTransferAccountOwnership:
+          begin
+            public_key := Model.TransferAccount.AccountKey;
+          end;
+
+          akaChangeAccountPrivateKey:
+          begin
+            public_key := Model.ChangeAccountPrivateKey.NewWalletKey.AccountKey;
+          end;
+
+        end;
+
+        errors := 'Public key: ' + 'Error encrypting';
+
+        if Model.TransferAccount.AccountKey.EC_OpenSSL_NID <>
+          CT_Account_NUL.accountInfo.accountKey.EC_OpenSSL_NID then
+        begin
+          payload_encrypted := ECIESEncrypt(public_key, payload_u);
+          valid := payload_encrypted <> '';
+        end
+        else
+        begin
+          valid := False;
+          errors := 'Selected private key is not valid to encode';
+          exit;
+        end;
+      end;
+
+      akaEncryptWithPassword:
+      begin
+        payload_encrypted := TAESComp.EVP_Encrypt_AES256(
+          payload_u, Model.Payload.Password);
+        valid := payload_encrypted <> '';
+      end;
+
+      akaNotEncrypt:
+      begin
+        payload_encrypted := payload_u;
+        valid := True;
+      end
+
+      else
+      begin
+        raise Exception.Create('Invalid Encryption Selection');
+      end;
+    end;
+
+  finally
+    if valid then
+    begin
+      if length(payload_encrypted) > CT_MaxPayloadSize then
+      begin
+        valid := False;
+        errors := 'Payload size is bigger than ' + IntToStr(CT_MaxPayloadSize) +
+          ' (' + IntToStr(length(payload_encrypted)) + ')';
+      end;
+
+    end;
+    Model.Payload.EncodedBytes := payload_encrypted;
+    Result := valid;
+  end;
+
+end;
+
+function TWIZChangeKeyWizard.UpdateOperationOptions(var errors: string): boolean;
+var
+  iAcc, iWallet: integer;
+  sender_account, signer_account: TAccount;
+  publicKey: TAccountKey;
+  wk: TWalletKey;
+  e: string;
+  amount: int64;
+begin
+  Result := False;
+  errors := '';
+  if not Assigned(TWallet.Keys) then
+  begin
+    errors := 'No wallet keys';
+    Exit;
+  end;
+
+  if Length(Model.Account.SelectedAccounts) = 0 then
+  begin
+    errors := 'No sender account';
+    Exit;
+  end
+  else
+  begin
+
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+    begin
+      sender_account := Model.Account.SelectedAccounts[iAcc];
+      iWallet := TWallet.Keys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
+      if (iWallet < 0) then
+      begin
+        errors := 'Private key of account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account) +
+          ' not found in wallet';
+        Exit;
+      end;
+      wk := TWallet.Keys.Key[iWallet];
+      if not assigned(wk.PrivateKey) then
+      begin
+        if wk.CryptedKey <> '' then
+        begin
+          // TODO: handle unlocking of encrypted wallet here
+          errors := 'Wallet is password protected. Need password';
+        end
+        else
+        begin
+          errors := 'Only public key of account ' +
+            TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account) +
+            ' found in wallet. You cannot operate with this account';
+        end;
+        Exit;
+      end;
+    end;
+  end;
+
+  Result := UpdateOpChangeKey(Model.Account.SelectedAccounts[0], signer_account,
+    publicKey, errors);
+  UpdatePayload(sender_account, e);
+end;
+
+function TWIZChangeKeyWizard.UpdateOpChangeKey(const TargetAccount: TAccount; var SignerAccount: TAccount; var NewPublicKey: TAccountKey; var errors: ansistring): boolean;
+
+begin
+  Result := False;
+  errors := '';
+  try
+
+    case Model.ChangeKey.ChangeKeyMode of
+      akaTransferAccountOwnership:
+      begin
+        NewPublicKey := Model.TransferAccount.AccountKey;
+      end;
+
+      akaChangeAccountPrivateKey:
+      begin
+        NewPublicKey := Model.ChangeAccountPrivateKey.NewWalletKey.AccountKey;
+      end;
+
+    end;
+
+    if TNode.Node.Bank.SafeBox.CurrentProtocol >= 1 then
+    begin
+      // Signer:
+      SignerAccount := Model.Signer.SignerAccount;
+      if (TAccountComp.IsAccountLocked(SignerAccount.accountInfo,
+        TNode.Node.Bank.BlocksCount)) then
+      begin
+        errors := 'Signer account ' + TAccountComp.AccountNumberToAccountTxtNumber(
+          SignerAccount.account) + ' is locked until block ' + IntToStr(
+          SignerAccount.accountInfo.locked_until_block);
+        exit;
+      end;
+      if (not TAccountComp.EqualAccountKeys(
+        SignerAccount.accountInfo.accountKey, TargetAccount.accountInfo.accountKey)) then
+      begin
+        errors := 'Signer account ' + TAccountComp.AccountNumberToAccountTxtNumber(
+          SignerAccount.account) + ' is not owner of account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account);
+        exit;
+      end;
+    end
+    else
+    begin
+      SignerAccount := TargetAccount;
+    end;
+
+    if (TAccountComp.EqualAccountKeys(TargetAccount.accountInfo.accountKey,
+      NewPublicKey)) then
+    begin
+      errors := 'New key is same as current key';
+      exit;
+    end;
+
+  finally
+    Result := errors = '';
+  end;
+end;
+
+procedure TWIZChangeKeyWizard.WIZChangeKeyOwnership();
+var
+  _V2, dooperation: boolean;
+  iAcc, i: integer;
+  _totalamount, _totalfee, _totalSignerFee, _amount, _fee: int64;
+  _signer_n_ops: cardinal;
+  operationstxt, operation_to_string, errors, auxs: string;
+  wk: TWalletKey;
+  ops: TOperationsHashTree;
+  op: TPCOperation;
+  account, signerAccount: TAccount;
+  _newOwnerPublicKey: TECDSA_Public;
+label
+  loop_start;
+begin
+  if not Assigned(TWallet.Keys) then
+    raise Exception.Create('No wallet keys');
+  if not UpdateOperationOptions(errors) then
+    raise Exception.Create(errors);
+  ops := TOperationsHashTree.Create;
+
+  try
+    _V2 := TNode.Node.Bank.SafeBox.CurrentProtocol >= CT_PROTOCOL_2;
+    _totalamount := 0;
+    _totalfee := 0;
+    _totalSignerFee := 0;
+    _signer_n_ops := 0;
+    operationstxt := '';
+    operation_to_string := '';
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+    begin
+      loop_start:
+        op := nil;
+      account := Model.Account.SelectedAccounts[iAcc];
+      if not UpdatePayload(account, errors) then
+      begin
+        raise Exception.Create('Error encoding payload of sender account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(account.account) + ': ' + errors);
+      end;
+      i := TWallet.Keys.IndexOfAccountKey(account.accountInfo.accountKey);
+      if i < 0 then
+      begin
+        raise Exception.Create('Sender account private key not found in Wallet');
+      end;
+
+      wk := TWallet.Keys.Key[i];
+      dooperation := True;
+      // Default fee
+      if account.balance > uint64(Model.Fee.DefaultFee) then
+        _fee := Model.Fee.DefaultFee
+      else
+        _fee := account.balance;
+
+      if not UpdateOpChangeKey(account, signerAccount, _newOwnerPublicKey, errors) then
+      begin
+        raise Exception.Create(errors);
+      end;
+      if _V2 then
+      begin
+        // must ensure is Signer account last if included in sender accounts (not necessarily ordered enumeration)
+        if (iAcc < Length(Model.Account.SelectedAccounts) - 1) and
+          (account.account = signerAccount.account) then
+        begin
+          TArrayTool<TAccount>.Swap(Model.Account.SelectedAccounts, iAcc,
+            Length(Model.Account.SelectedAccounts) - 1); // ensure signer account processed last
+          // TArrayTool_internal<Cardinal>.Swap(_senderAccounts, iAcc, Length(_senderAccounts) - 1);
+          goto loop_start; // TODO: remove ugly hack with refactoring!
+        end;
+
+        // Maintain correct signer fee distribution
+        if uint64(_totalSignerFee) >= signerAccount.balance then
+          _fee := 0
+        else if signerAccount.balance - uint64(_totalSignerFee) >
+          uint64(Model.Fee.DefaultFee) then
+          _fee := Model.Fee.DefaultFee
+        else
+          _fee := signerAccount.balance - uint64(_totalSignerFee);
+        op := TOpChangeKeySigned.Create(signerAccount.account,
+          signerAccount.n_operation + _signer_n_ops + 1, account.account,
+          wk.PrivateKey, _newOwnerPublicKey, _fee, Model.Payload.EncodedBytes);
+        Inc(_signer_n_ops);
+        Inc(_totalSignerFee, _fee);
+      end
+      else
+      begin
+        op := TOpChangeKey.Create(account.account, account.n_operation +
+          1, account.account, wk.PrivateKey, _newOwnerPublicKey, _fee, Model.Payload.EncodedBytes);
+      end;
+      Inc(_totalfee, _fee);
+      operationstxt :=
+        'Change private key to ' + TAccountComp.GetECInfoTxt(
+        _newOwnerPublicKey.EC_OpenSSL_NID);
+
+      if Assigned(op) and (dooperation) then
+      begin
+        ops.AddOperationToHashTree(op);
+        if operation_to_string <> '' then
+          operation_to_string := operation_to_string + #10;
+        operation_to_string := operation_to_string + op.ToString;
+      end;
+      FreeAndNil(op);
+    end;
+
+    if (ops.OperationsCount = 0) then
+      raise Exception.Create('No valid operation to execute');
+
+    if (Length(Model.Account.SelectedAccounts) > 1) then
+    begin
+      auxs := '';
+      if Application.MessageBox(
+        PChar('Execute ' + IntToStr(Length(Model.Account.SelectedAccounts)) +
+        ' operations?' + #10 + 'Operation: ' + operationstxt + #10 +
+        auxs + 'Total fee: ' + TAccountComp.FormatMoney(_totalfee) +
+        #10 + #10 + 'Note: This operation will be transmitted to the network!'),
+        PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+        idYes then
+      begin
+        Exit;
+      end;
+    end
+    else
+    begin
+      if Application.MessageBox(PChar('Execute this operation:' + #10 +
+        #10 + operation_to_string + #10 + #10 +
+        'Note: This operation will be transmitted to the network!'),
+        PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <> idYes then
+      begin
+        Exit;
+      end;
+    end;
+    i := TNode.Node.AddOperations(nil, ops, nil, errors);
+    if (i = ops.OperationsCount) then
+    begin
+      operationstxt := 'Successfully executed ' + IntToStr(i) +
+        ' operations!' + #10 + #10 + operation_to_string;
+      if i > 1 then
+      begin
+
+        ShowMessage(operationstxt);
+      end
+      else
+      begin
+        Application.MessageBox(
+          PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
+          #10 + #10 + operation_to_string),
+          PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
+      end;
+
+    end
+    else if (i > 0) then
+    begin
+      operationstxt := 'One or more of your operations has not been executed:' +
+        #10 + 'Errors:' + #10 + errors + #10 + #10 +
+        'Total successfully executed operations: ' + IntToStr(i);
+
+      ShowMessage(operationstxt);
+    end
+    else
+    begin
+      raise Exception.Create(errors);
+    end;
+
+
+  finally
+    ops.Free;
+  end;
+
+end;
+
+constructor TWIZChangeKeyWizard.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner, [TWIZChangeKey_ConfirmAccount,
+    TWIZChangeKey_Confirmation]);
+  TitleText := 'Change Key';
+  FinishText := 'Change Key';
+end;
+
+function TWIZChangeKeyWizard.DetermineHasNext: boolean;
+begin
+  Result := not (CurrentScreen is TWIZChangeKey_Confirmation);
+end;
+
+function TWIZChangeKeyWizard.DetermineHasPrevious: boolean;
+begin
+  Result := inherited DetermineHasPrevious;
+end;
+
+function TWIZChangeKeyWizard.FinishRequested(out message: ansistring): boolean;
+begin
+  // Execute the Change Key Action here
+  try
+    Result := True;
+    WIZChangeKeyOwnership();
+  except
+    On E: Exception do
+    begin
+      Result := False;
+      message := E.ToString;
+    end;
+  end;
+end;
+
+function TWIZChangeKeyWizard.CancelRequested(out message: ansistring): boolean;
+begin
+  Result := True;
+end;
+
+end.

+ 50 - 0
src/gui/wizards/operations/UWIZChangeKey_ConfirmAccount.lfm

@@ -0,0 +1,50 @@
+object WIZChangeKey_ConfirmAccount: TWIZChangeKey_ConfirmAccount
+  Left = 0
+  Height = 261
+  Top = 0
+  Width = 429
+  Caption = 'ChangeKey_ConfirmAccount'
+  ClientHeight = 261
+  ClientWidth = 429
+  LCLVersion = '1.8.2.0'
+  Visible = False
+  object gpChangeKey: TGroupBox
+    Left = 4
+    Height = 256
+    Top = 0
+    Width = 420
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    Caption = 'Change Key Accounts'
+    ClientHeight = 236
+    ClientWidth = 416
+    TabOrder = 0
+    object paGrid: TPanel
+      Left = 8
+      Height = 192
+      Top = 24
+      Width = 400
+      Anchors = [akTop, akLeft, akRight, akBottom]
+      BevelOuter = bvNone
+      Caption = 'GRID PANEL'
+      TabOrder = 0
+    end
+    object lblTotalBalances: TLabel
+      Left = 8
+      Height = 15
+      Top = 0
+      Width = 176
+      Caption = 'Selected Accounts Total Balance: '
+      ParentColor = False
+    end
+    object lblTotalBalanceValue: TLabel
+      Left = 192
+      Height = 15
+      Top = 0
+      Width = 70
+      Caption = 'Total Balance'
+      Font.Color = clGreen
+      ParentColor = False
+      ParentFont = False
+    end
+  end
+end

+ 144 - 0
src/gui/wizards/operations/UWIZChangeKey_ConfirmAccount.pas

@@ -0,0 +1,144 @@
+unit UWIZChangeKey_ConfirmAccount;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UVisualGrid, UCommon.Data, UCellRenderers,
+  UWizard, UWIZSendPASC, UWIZChangeKey_SelectOption, UWIZChangeKey_Confirmation, UWIZModels;
+
+type
+
+  { TWIZChangeKey_ConfirmAccount }
+
+  TWIZChangeKey_ConfirmAccount = class(TWizardForm<TWIZOperationsModel>)
+    gpChangeKey: TGroupBox;
+    lblTotalBalances: TLabel;
+    lblTotalBalanceValue: TLabel;
+    paGrid: TPanel;
+  private
+    FChangeKeyGrid: TVisualGrid;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, UCoreUtils, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+type
+
+  { TAccountChangeKeyDataSource }
+
+  TAccountChangeKeyDataSource = class(TAccountsDataSourceBase)
+  private
+    FModel: TWIZOperationsModel;
+  public
+    property Model: TWIZOperationsModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
+  end;
+
+{ TWIZChangeKey_ConfirmAccount }
+
+procedure TWIZChangeKey_ConfirmAccount.OnPresent;
+var
+  Data: TAccountChangeKeyDataSource;
+  i: integer;
+  acc: TAccount;
+  totalBalance: int64;
+begin
+  FChangeKeyGrid := TVisualGrid.Create(Self);
+  FChangeKeyGrid.CanSearch := False;
+  FChangeKeyGrid.SortMode := smMultiColumn;
+  FChangeKeyGrid.FetchDataInThread := False;
+  FChangeKeyGrid.AutoPageSize := True;
+  FChangeKeyGrid.SelectionType := stNone;
+  FChangeKeyGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
+  with FChangeKeyGrid.AddColumn('Account') do
+  begin
+    StretchedToFill := True;
+    Binding := 'AccountNumber';
+    SortBinding := 'AccountNumber';
+    DisplayBinding := 'Account';
+    Width := 100;
+    HeaderFontStyles := [fsBold];
+    DataFontStyles := [fsBold];
+    Filters := SORTABLE_NUMERIC_FILTER;
+  end;
+  with FChangeKeyGrid.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 := TAccountChangeKeyDataSource.Create(FChangeKeyGrid);
+  Data.Model := Model;
+  FChangeKeyGrid.DataSource := Data;
+  paGrid.AddControlDockCenter(FChangeKeyGrid);
+
+  totalBalance := 0;
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    acc := Model.Account.SelectedAccounts[i];
+    totalBalance := totalBalance + acc.balance;
+  end;
+
+  lblTotalBalanceValue.Caption :=
+    Format('%s PASC', [TAccountComp.FormatMoney(totalBalance)]);
+end;
+
+procedure TWIZChangeKey_ConfirmAccount.OnNext;
+begin
+  UpdatePath(ptReplaceAllNext, [TWIZChangeKey_SelectOption, TWIZChangeKey_Confirmation]);
+end;
+
+function TWIZChangeKey_ConfirmAccount.Validate(out message: ansistring): boolean;
+begin
+  Result := True;
+  // get signer accounts from selected accounts
+  Model.Signer.SignerCandidates := TCoreTool.GetSignerCandidates(Length(Model.Account.SelectedAccounts), Model.Account.SelectedAccounts);
+
+  if Length(Model.Signer.SignerCandidates) < 1 then
+  begin
+    Result := False;
+    message := 'no valid signer account was found.';
+  end;
+
+end;
+
+{ TAccountChangeKeyDataSource }
+
+procedure TAccountChangeKeyDataSource.FetchAll(const AContainer: TList<TAccount>);
+var
+  i: integer;
+begin
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    AContainer.Add(Model.Account.SelectedAccounts[i]);
+  end;
+end;
+
+end.

+ 48 - 0
src/gui/wizards/operations/UWIZChangeKey_Confirmation.lfm

@@ -0,0 +1,48 @@
+object WIZChangeKey_Confirmation: TWIZChangeKey_Confirmation
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZChangeKey_Confirmation'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.2.0'
+  Visible = False
+  object GroupBox1: TGroupBox
+    Left = 10
+    Height = 232
+    Top = 8
+    Width = 408
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    Caption = 'Confirm Change Key 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 lblSgnAcc: TLabel
+      Left = 112
+      Height = 15
+      Top = 10
+      Width = 53
+      Caption = 'lblSgnAcc'
+      ParentColor = False
+    end
+    object Label1: TLabel
+      Left = 8
+      Height = 15
+      Top = 10
+      Width = 84
+      Caption = 'Signer Account:'
+      ParentColor = False
+    end
+  end
+end

+ 178 - 0
src/gui/wizards/operations/UWIZChangeKey_Confirmation.pas

@@ -0,0 +1,178 @@
+unit UWIZChangeKey_Confirmation;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UVisualGrid, UCellRenderers, UCommon.Data, UWizard, UWIZChangeKey, UWIZModels;
+
+type
+
+  { TWIZChangeKey_Confirmation }
+
+  TWIZChangeKey_Confirmation = class(TWizardForm<TWIZOperationsModel>)
+    GroupBox1: TGroupBox;
+    Label1: TLabel;
+    lblSgnAcc: TLabel;
+    paGrid: TPanel;
+  private
+    FChangeKeyGrid: TVisualGrid;
+  public
+    procedure OnPresent; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, UCrypto, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+type
+
+  { TAccountChangeKeyDataSource }
+
+  TAccountChangeKeyDataSource = class(TAccountsDataSourceBase)
+  private
+    FModel: TWIZOperationsModel;
+  protected
+    function GetColumns: TDataColumns; override;
+  public
+    property Model: TWIZOperationsModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
+    function GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant; override;
+  end;
+
+{ TWIZChangeKey_Confirmation }
+
+procedure TWIZChangeKey_Confirmation.OnPresent;
+var
+  Data: TAccountChangeKeyDataSource;
+begin
+  FChangeKeyGrid := TVisualGrid.Create(Self);
+  FChangeKeyGrid.CanSearch := False;
+  FChangeKeyGrid.SortMode := smMultiColumn;
+  FChangeKeyGrid.FetchDataInThread := False;
+  FChangeKeyGrid.AutoPageSize := True;
+  FChangeKeyGrid.SelectionType := stNone;
+  FChangeKeyGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
+
+  with FChangeKeyGrid.AddColumn('Account') do
+  begin
+    Binding := 'Account';
+    Filters := SORTABLE_NUMERIC_FILTER;
+    Width := 100;
+    HeaderFontStyles := [fsBold];
+    DataFontStyles := [fsBold];
+  end;
+
+  with FChangeKeyGrid.AddColumn('Current Key') do
+  begin
+    Binding := 'CurrentKey';
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+
+  with FChangeKeyGrid.AddColumn('New Key') do
+  begin
+    Binding := 'NewKey';
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+
+  with FChangeKeyGrid.AddColumn('Fee') do
+  begin
+    Filters := SORTABLE_TEXT_FILTER;
+    Width := 100;
+  end;
+
+  Data := TAccountChangeKeyDataSource.Create(FChangeKeyGrid);
+  Data.Model := Model;
+  FChangeKeyGrid.DataSource := Data;
+  paGrid.AddControlDockCenter(FChangeKeyGrid);
+  lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.Signer.SignerAccount.account);
+end;
+
+{ TAccountChangeKeyDataSource }
+
+function TAccountChangeKeyDataSource.GetColumns: TDataColumns;
+begin
+  Result := TDataColumns.Create(
+    TDataColumn.From('Account'),
+    TDataColumn.From('CurrentKey'),
+    TDataColumn.From('NewKey'),
+    TDataColumn.From('Fee')
+    );
+end;
+
+function TAccountChangeKeyDataSource.GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant;
+var
+  index: integer;
+begin
+  if ABindingName = 'Account' then
+    Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
+  else if ABindingName = 'Fee' then
+    Result := TAccountComp.FormatMoney(Model.Fee.SingleOperationFee)
+  else
+  begin
+    case Model.ChangeKey.ChangeKeyMode of
+      akaTransferAccountOwnership:
+      begin
+        if ABindingName = 'CurrentKey' then
+          Result := TAccountComp.AccountPublicKeyExport(AItem.accountInfo.accountKey)
+        else if ABindingName = 'NewKey' then
+          Result := TAccountComp.AccountPublicKeyExport(Model.TransferAccount.AccountKey)
+        else
+          raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
+      end;
+
+      akaChangeAccountPrivateKey:
+      begin
+        if ABindingName = 'CurrentKey' then
+          { TODO : Check how to get the wallet name an account is in }
+          Result := '??? unknown'
+        else if ABindingName = 'NewKey' then
+        begin
+          Result := IIF(Model.ChangeAccountPrivateKey.NewWalletKey.Name = '',
+            TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(
+            Model.ChangeAccountPrivateKey.NewWalletKey.AccountKey)), Model.ChangeAccountPrivateKey.NewWalletKey.Name);
+          if not Assigned(Model.ChangeAccountPrivateKey.NewWalletKey.PrivateKey) then
+          begin
+            Result := Result + '(*)';
+          end;
+        end
+        else
+          raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
+      end;
+
+    end;
+  end;
+
+end;
+
+
+procedure TAccountChangeKeyDataSource.FetchAll(const AContainer: TList<TAccount>);
+var
+  i: integer;
+begin
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    AContainer.Add(Model.Account.SelectedAccounts[i]);
+  end;
+end;
+
+
+end.

+ 53 - 0
src/gui/wizards/operations/UWIZChangeKey_EnterKey.lfm

@@ -0,0 +1,53 @@
+object WIZChangeKey_EnterKey: TWIZChangeKey_EnterKey
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = chkChooseFee
+  Caption = 'ChangeKey_EnterKey'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.2.0'
+  Visible = False
+  object gbNewPublicKey: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 400
+    Caption = 'New Public Key'
+    ClientHeight = 212
+    ClientWidth = 396
+    TabOrder = 0
+    object lblPublicKeyNotice: TLabel
+      Left = 8
+      Height = 30
+      Top = 7
+      Width = 348
+      Caption = 'Please enter the public key of the new owner who will control this '#13#10'account'
+      ParentColor = False
+    end
+    object chkChooseFee: TCheckBox
+      Left = 8
+      Height = 19
+      Top = 152
+      Width = 226
+      Caption = 'Let me choose fee''s for this transaction'
+      TabOrder = 0
+    end
+    object chkAttachPayload: TCheckBox
+      Left = 8
+      Height = 19
+      Top = 184
+      Width = 303
+      Caption = 'I want to attach a message payload to this transaction'
+      TabOrder = 1
+    end
+    object mmoNewPrivateKey: TMemo
+      Left = 8
+      Height = 102
+      Top = 42
+      Width = 376
+      TabOrder = 2
+    end
+  end
+end

+ 97 - 0
src/gui/wizards/operations/UWIZChangeKey_EnterKey.pas

@@ -0,0 +1,97 @@
+unit UWIZChangeKey_EnterKey;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UCommon, UCommon.Collections, UWallet,
+  UFRMAccountSelect, UNode, UWizard, UWIZFeeOverride, UWIZPayloadOverride, UWIZSelectSignerOverride,
+  UWIZChangeKey_Confirmation, UWIZModels;
+
+type
+
+  { TWIZChangeKey_EnterKey }
+
+  TWIZChangeKey_EnterKey = class(TWizardForm<TWIZOperationsModel>)
+    chkChooseFee: TCheckBox;
+    chkAttachPayload: TCheckBox;
+    gbNewPublicKey: TGroupBox;
+    lblPublicKeyNotice: TLabel;
+    mmoNewPrivateKey: TMemo;
+
+  public
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UUserInterface, USettings;
+
+{ TWIZChangeKey_EnterKey }
+
+procedure TWIZChangeKey_EnterKey.OnNext;
+begin
+  Model.Payload.HasPayload := chkAttachPayload.Checked;
+
+  if chkChooseFee.Checked then
+  begin
+    UpdatePath(ptReplaceAllNext, [TWIZFeeOverride, TWIZChangeKey_Confirmation]);
+  end
+  else
+  begin
+    Model.Fee.SingleOperationFee := TSettings.DefaultFee;
+    if Model.Payload.HasPayload then
+    begin
+      UpdatePath(ptReplaceAllNext, [TWIZPayloadOverride, TWIZChangeKey_Confirmation]);
+    end
+    else
+    begin
+      UpdatePath(ptReplaceAllNext, [TWIZSelectSignerOverride, TWIZChangeKey_Confirmation]);
+    end;
+  end;
+end;
+
+function TWIZChangeKey_EnterKey.Validate(out message: ansistring): boolean;
+var
+  tempAccountKey: TAccountKey;
+  i: Integer;
+begin
+  Result := True;
+  if not TAccountComp.AccountKeyFromImport(mmoNewPrivateKey.Lines.Text,
+    tempAccountKey, message) then
+  begin
+    Result := False;
+    Exit;
+  end;
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    if TAccountComp.EqualAccountKeys(Model.Account.SelectedAccounts[i].accountInfo.accountKey,
+      tempAccountKey) then
+    begin
+      Result := False;
+      message := 'New key is same as current key';
+      Exit;
+    end;
+  end;
+  Model.TransferAccount.AccountKey := tempAccountKey;
+end;
+
+end.

+ 65 - 0
src/gui/wizards/operations/UWIZChangeKey_SelectKey.lfm

@@ -0,0 +1,65 @@
+object WIZChangeKey_SelectKey: TWIZChangeKey_SelectKey
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZChangeKey_SelectKey'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.2.0'
+  Visible = False
+  object gbNewPrivateKey: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 400
+    Caption = 'New Private Key'
+    ClientHeight = 212
+    ClientWidth = 396
+    TabOrder = 0
+    object lblPrivateKeyNote: TLabel
+      Left = 8
+      Height = 15
+      Top = 8
+      Width = 329
+      Caption = 'Please select the new private key to update your accounts with'
+      ParentColor = False
+    end
+    object cbNewPrivateKey: TComboBox
+      Left = 8
+      Height = 23
+      Top = 40
+      Width = 168
+      ItemHeight = 15
+      OnChange = cbNewPrivateKeyChange
+      TabOrder = 0
+      Text = 'Select Private Key'
+    end
+    object lblKeyName: TLabel
+      Left = 192
+      Height = 15
+      Top = 45
+      Width = 128
+      Caption = 'Please Select Private Key'
+      Font.Color = clRed
+      ParentColor = False
+      ParentFont = False
+    end
+    object chkChooseFee: TCheckBox
+      Left = 8
+      Height = 19
+      Top = 80
+      Width = 226
+      Caption = 'Let me choose fee''s for this transaction'
+      TabOrder = 1
+    end
+    object chkAttachPayload: TCheckBox
+      Left = 8
+      Height = 19
+      Top = 112
+      Width = 303
+      Caption = 'I want to attach a message payload to this transaction'
+      TabOrder = 2
+    end
+  end
+end

+ 163 - 0
src/gui/wizards/operations/UWIZChangeKey_SelectKey.pas

@@ -0,0 +1,163 @@
+unit UWIZChangeKey_SelectKey;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UCommon, UCommon.Collections, UWallet,
+  UFRMAccountSelect, UNode, UWizard,
+  UWIZChangeKey_Confirmation, UWIZFeeOverride, UWIZSelectSignerOverride, UWIZPayloadOverride, UWIZModels;
+
+type
+
+  { TWIZChangeKey_SelectKey }
+
+  TWIZChangeKey_SelectKey = class(TWizardForm<TWIZOperationsModel>)
+    cbNewPrivateKey: TComboBox;
+    chkAttachPayload: TCheckBox;
+    chkChooseFee: TCheckBox;
+    gbNewPrivateKey: TGroupBox;
+    lblKeyName: TLabel;
+    lblPrivateKeyNote: TLabel;
+    procedure cbNewPrivateKeyChange(Sender: TObject);
+  private
+    procedure UpdateWalletKeys();
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UCrypto, UUserInterface, USettings;
+
+{ TWIZChangeKey_SelectKey }
+
+procedure TWIZChangeKey_SelectKey.cbNewPrivateKeyChange(Sender: TObject);
+var
+  i: integer;
+  wk: TWalletKey;
+begin
+  if cbNewPrivateKey.ItemIndex < 1 then
+  begin
+    lblKeyName.Font.Color := clRed;
+    lblKeyName.Caption := 'Please Select Private Key';
+  end
+  else
+  begin
+    lblKeyName.Font.Color := clGreen;
+    i := PtrInt(cbNewPrivateKey.Items.Objects[cbNewPrivateKey.ItemIndex]);
+    wk := TWallet.Keys.Key[i];
+    lblKeyName.Caption := Format('%s ',
+      [IIF(wk.Name = '', TCrypto.ToHexaString(
+      TAccountComp.AccountKey2RawString(wk.AccountKey)), wk.Name)]);
+  end;
+end;
+
+procedure TWIZChangeKey_SelectKey.UpdateWalletKeys();
+var
+  i: integer;
+  wk: TWalletKey;
+  s: string;
+begin
+  cbNewPrivateKey.items.BeginUpdate;
+  try
+    cbNewPrivateKey.Items.Clear;
+    cbNewPrivateKey.Items.Add('Select Private Key');
+    if not Assigned(TWallet.Keys) then
+    begin
+      Exit;
+    end;
+    for i := 0 to TWallet.Keys.Count - 1 do
+    begin
+      wk := TWallet.Keys.Key[i];
+      s := IIF(wk.Name = '', TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(wk.AccountKey)), wk.Name);
+      if not Assigned(wk.PrivateKey) then
+      begin
+        s := s + '(*)';
+      end;
+      cbNewPrivateKey.Items.AddObject(s, TObject(i));
+    end;
+    cbNewPrivateKey.Sorted := True;
+  finally
+    cbNewPrivateKey.Items.EndUpdate;
+  end;
+end;
+
+procedure TWIZChangeKey_SelectKey.OnPresent;
+begin
+  UpdateWalletKeys();
+  cbNewPrivateKey.ItemIndex := Model.ChangeAccountPrivateKey.SelectedIndex;
+  cbNewPrivateKeyChange(Self);
+end;
+
+procedure TWIZChangeKey_SelectKey.OnNext;
+begin
+  Model.ChangeAccountPrivateKey.SelectedIndex := cbNewPrivateKey.ItemIndex;
+  Model.ChangeAccountPrivateKey.NewWalletKey := TWallet.Keys.Key[PtrInt(cbNewPrivateKey.Items.Objects[cbNewPrivateKey.ItemIndex])];
+  Model.Payload.HasPayload := chkAttachPayload.Checked;
+
+  if chkChooseFee.Checked then
+  begin
+    UpdatePath(ptReplaceAllNext, [TWIZFeeOverride, TWIZChangeKey_Confirmation]);
+  end
+  else
+  begin
+    Model.Fee.SingleOperationFee := TSettings.DefaultFee;
+    if Model.Payload.HasPayload then
+    begin
+      UpdatePath(ptReplaceAllNext, [TWIZPayloadOverride, TWIZChangeKey_Confirmation]);
+    end
+    else
+    begin
+      UpdatePath(ptReplaceAllNext, [TWIZSelectSignerOverride, TWIZChangeKey_Confirmation]);
+    end;
+  end;
+end;
+
+function TWIZChangeKey_SelectKey.Validate(out message: ansistring): boolean;
+var
+  i: integer;
+  tempAccountKey: TAccountKey;
+begin
+  Result := True;
+  if cbNewPrivateKey.ItemIndex < 1 then
+  begin
+    message := 'A key must be selected';
+    Result := False;
+    Exit;
+  end;
+
+  tempAccountKey := TWallet.Keys.Key[PtrInt(cbNewPrivateKey.Items.Objects[cbNewPrivateKey.ItemIndex])].AccountKey;
+
+   for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    if TAccountComp.EqualAccountKeys(Model.Account.SelectedAccounts[i].accountInfo.accountKey,
+      tempAccountKey) then
+    begin
+      Result := False;
+      message := 'New key is same as current key';
+      Exit;
+    end;
+  end;
+end;
+
+end.

+ 63 - 0
src/gui/wizards/operations/UWIZChangeKey_SelectOption.lfm

@@ -0,0 +1,63 @@
+object WIZChangeKey_SelectOption: TWIZChangeKey_SelectOption
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  Caption = 'WIZChangeKey_SelectOption'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.8.2.0'
+  Visible = False
+  object gbChangeKeyOptions: TGroupBox
+    Left = 8
+    Height = 245
+    Top = 2
+    Width = 410
+    Caption = 'Change Key Options'
+    ClientHeight = 225
+    ClientWidth = 406
+    TabOrder = 0
+    object lblNote: TLabel
+      Left = 8
+      Height = 15
+      Top = 8
+      Width = 310
+      Caption = 'How would you like to change the keys of your account(s).'
+      ParentColor = False
+    end
+    object rbTransferAccountOwnership: TRadioButton
+      Left = 8
+      Height = 19
+      Top = 40
+      Width = 192
+      Caption = 'Transfer account to another user'
+      Checked = True
+      TabOrder = 1
+      TabStop = True
+    end
+    object lblTransferAccountOwnership: TLabel
+      Left = 8
+      Height = 15
+      Top = 72
+      Width = 351
+      Caption = 'Use this to transfer ownership of the account to another user''s key.'
+      ParentColor = False
+    end
+    object rbChangeAccountPrivateKey: TRadioButton
+      Left = 8
+      Height = 19
+      Top = 120
+      Width = 207
+      Caption = 'Change to another key in my wallet'
+      TabOrder = 0
+    end
+    object lblChangeAccountPrivateKey: TLabel
+      Left = 8
+      Height = 15
+      Top = 152
+      Width = 383
+      Caption = 'This will change the key of your account to another key that you control.'
+      ParentColor = False
+    end
+  end
+end

+ 63 - 0
src/gui/wizards/operations/UWIZChangeKey_SelectOption.pas

@@ -0,0 +1,63 @@
+unit UWIZChangeKey_SelectOption;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UWizard, UWIZChangeKey, UWIZModels, UWIZChangeKey_EnterKey, UWIZChangeKey_SelectKey, UWIZChangeKey_Confirmation;
+
+type
+
+  { TWIZChangeKey_SelectOption }
+
+  TWIZChangeKey_SelectOption = class(TWizardForm<TWIZOperationsModel>)
+    gbChangeKeyOptions: TGroupBox;
+    lblTransferAccountOwnership: TLabel;
+    lblNote: TLabel;
+    lblChangeAccountPrivateKey: TLabel;
+    rbTransferAccountOwnership: TRadioButton;
+    rbChangeAccountPrivateKey: TRadioButton;
+  public
+    procedure OnNext; override;
+  end;
+
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, USettings, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+{ TWIZChangeKey_SelectOption }
+
+procedure TWIZChangeKey_SelectOption.OnNext;
+begin
+  if rbTransferAccountOwnership.Checked then
+  begin
+    Model.ChangeKey.ChangeKeyMode := akaTransferAccountOwnership;
+    UpdatePath(ptReplaceAllNext, [TWIZChangeKey_EnterKey,
+      TWIZChangeKey_Confirmation]);
+  end
+  else if rbChangeAccountPrivateKey.Checked then
+  begin
+    Model.ChangeKey.ChangeKeyMode := akaChangeAccountPrivateKey;
+    UpdatePath(ptReplaceAllNext, [TWIZChangeKey_SelectKey,
+      TWIZChangeKey_Confirmation]);
+  end;
+end;
+
+end.

+ 453 - 0
src/gui/wizards/operations/UWIZConfirmAccount.pas

@@ -0,0 +1,453 @@
+unit UWIZChangeKey;
+
+{$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.
+
+  Acknowledgements:
+    Herman Schoenfeld <[email protected]>: added grid-based layout
+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Dialogs, UCrypto, UCommon, UWizard, UAccounts, LCLType, UWIZModels;
+
+type
+
+  { TWIZChangeKeyWizard }
+
+  TWIZChangeKeyWizard = class(TWizard<TWIZOperationsModel>)
+  private
+    function UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
+    function UpdateOperationOptions(var errors: string): boolean;
+    function UpdateOpChangeKey(const TargetAccount: TAccount; var SignerAccount: TAccount; var NewPublicKey: TAccountKey; var errors: ansistring): boolean;
+    procedure WIZChangeKeyOwnership();
+  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,
+  UWIZChangeKey_Start,
+  UWIZChangeKey_Confirmation;
+
+{ TWIZChangeKeyWizard }
+
+function TWIZChangeKeyWizard.UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
+var
+  valid: boolean;
+  payload_encrypted, payload_u: string;
+  account: TAccount;
+begin
+  valid := False;
+  payload_encrypted := '';
+  Model.Payload.EncodedBytes := '';
+  errors := 'Unknown error';
+  payload_u := Model.Payload.Content;
+
+  try
+    if (payload_u = '') then
+    begin
+      valid := True;
+      Exit;
+    end;
+    case Model.Payload.Mode of
+
+      akaEncryptWithSender:
+      begin
+        // Use sender
+        errors := 'Error encrypting';
+        account := SenderAccount;
+        payload_encrypted := ECIESEncrypt(account.accountInfo.accountKey, payload_u);
+        valid := payload_encrypted <> '';
+      end;
+
+      akaEncryptWithReceiver:
+      begin
+        errors := 'Public key: ' + 'Error encrypting';
+
+        if Model.WIZChangeKey.AccountKey.EC_OpenSSL_NID <>
+          CT_Account_NUL.accountInfo.accountKey.EC_OpenSSL_NID then
+        begin
+          payload_encrypted := ECIESEncrypt(Model.WIZChangeKey.AccountKey, payload_u);
+          valid := payload_encrypted <> '';
+        end
+        else
+        begin
+          valid := False;
+          errors := 'Selected private key is not valid to encode';
+          exit;
+        end;
+      end;
+
+      akaEncryptWithPassword:
+      begin
+        payload_encrypted := TAESComp.EVP_Encrypt_AES256(
+          payload_u, Model.Payload.Password);
+        valid := payload_encrypted <> '';
+      end;
+
+      akaNotEncrypt:
+      begin
+        payload_encrypted := payload_u;
+        valid := True;
+      end
+
+      else
+      begin
+        raise Exception.Create('Invalid Encryption Selection');
+      end;
+    end;
+
+  finally
+    if valid then
+    begin
+      if length(payload_encrypted) > CT_MaxPayloadSize then
+      begin
+        valid := False;
+        errors := 'Payload size is bigger than ' + IntToStr(CT_MaxPayloadSize) +
+          ' (' + IntToStr(length(payload_encrypted)) + ')';
+      end;
+
+    end;
+    Model.Payload.EncodedBytes := payload_encrypted;
+    Result := valid;
+  end;
+
+end;
+
+function TWIZChangeKeyWizard.UpdateOperationOptions(var errors: string): boolean;
+var
+  iAcc, iWallet: integer;
+  sender_account, signer_account: TAccount;
+  publicKey: TAccountKey;
+  wk: TWalletKey;
+  e: string;
+  amount: int64;
+begin
+  Result := False;
+  errors := '';
+  if not Assigned(TWallet.Keys) then
+  begin
+    errors := 'No wallet keys';
+    Exit;
+  end;
+
+  if Length(Model.WIZChangeKey.SelectedAccounts) = 0 then
+  begin
+    errors := 'No sender account';
+    Exit;
+  end
+  else
+  begin
+
+    for iAcc := Low(Model.WIZChangeKey.SelectedAccounts) to High(Model.WIZChangeKey.SelectedAccounts) do
+    begin
+      sender_account := Model.WIZChangeKey.SelectedAccounts[iAcc];
+      iWallet := TWallet.Keys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
+      if (iWallet < 0) then
+      begin
+        errors := 'Private key of account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account) +
+          ' not found in wallet';
+        Exit;
+      end;
+      wk := TWallet.Keys.Key[iWallet];
+      if not assigned(wk.PrivateKey) then
+      begin
+        if wk.CryptedKey <> '' then
+        begin
+          // TODO: handle unlocking of encrypted wallet here
+          errors := 'Wallet is password protected. Need password';
+        end
+        else
+        begin
+          errors := 'Only public key of account ' +
+            TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account) +
+            ' found in wallet. You cannot operate with this account';
+        end;
+        Exit;
+      end;
+    end;
+  end;
+
+  Result := UpdateOpChangeKey(Model.WIZChangeKey.SelectedAccounts[0], signer_account,
+    publicKey, errors);
+  UpdatePayload(sender_account, e);
+end;
+
+function TWIZChangeKeyWizard.UpdateOpChangeKey(const TargetAccount: TAccount;
+  var SignerAccount: TAccount; var NewPublicKey: TAccountKey;
+  var errors: ansistring): boolean;
+begin
+  Result := False;
+  errors := '';
+  try
+    if not TAccountComp.AccountKeyFromImport(Model.WIZChangeKey.NewPublicKey,
+      NewPublicKey, errors) then
+    begin
+      Exit;
+    end;
+
+    if TNode.Node.Bank.SafeBox.CurrentProtocol >= 1 then
+    begin
+      // Signer:
+      SignerAccount := Model.Signer.SignerAccount;
+      if (TAccountComp.IsAccountLocked(SignerAccount.accountInfo,
+        TNode.Node.Bank.BlocksCount)) then
+      begin
+        errors := 'Signer account ' + TAccountComp.AccountNumberToAccountTxtNumber(
+          SignerAccount.account) + ' is locked until block ' + IntToStr(
+          SignerAccount.accountInfo.locked_until_block);
+        exit;
+      end;
+      if (not TAccountComp.EqualAccountKeys(
+        SignerAccount.accountInfo.accountKey, TargetAccount.accountInfo.accountKey)) then
+      begin
+        errors := 'Signer account ' + TAccountComp.AccountNumberToAccountTxtNumber(
+          SignerAccount.account) + ' is not owner of account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account);
+        exit;
+      end;
+    end
+    else
+    begin
+      SignerAccount := TargetAccount;
+    end;
+
+    if (TAccountComp.EqualAccountKeys(TargetAccount.accountInfo.accountKey,
+      NewPublicKey)) then
+    begin
+      errors := 'New public key is the same public key';
+      exit;
+    end;
+
+  finally
+    Result := errors = '';
+  end;
+end;
+
+procedure TWIZChangeKeyWizard.WIZChangeKeyOwnership();
+var
+  _V2, dooperation: boolean;
+  iAcc, i: integer;
+  _totalamount, _totalfee, _totalSignerFee, _amount, _fee: int64;
+  _signer_n_ops: cardinal;
+  operationstxt, operation_to_string, errors, auxs: string;
+  wk: TWalletKey;
+  ops: TOperationsHashTree;
+  op: TPCOperation;
+  account, signerAccount: TAccount;
+  _newOwnerPublicKey: TECDSA_Public;
+label
+  loop_start;
+begin
+  if not Assigned(TWallet.Keys) then
+    raise Exception.Create('No wallet keys');
+  if not UpdateOperationOptions(errors) then
+    raise Exception.Create(errors);
+  ops := TOperationsHashTree.Create;
+
+  try
+    _V2 := TNode.Node.Bank.SafeBox.CurrentProtocol >= CT_PROTOCOL_2;
+    _totalamount := 0;
+    _totalfee := 0;
+    _totalSignerFee := 0;
+    _signer_n_ops := 0;
+    operationstxt := '';
+    operation_to_string := '';
+    for iAcc := Low(Model.WIZChangeKey.SelectedAccounts) to High(Model.WIZChangeKey.SelectedAccounts) do
+    begin
+      loop_start:
+        op := nil;
+      account := Model.WIZChangeKey.SelectedAccounts[iAcc];
+      if not UpdatePayload(account, errors) then
+      begin
+        raise Exception.Create('Error encoding payload of sender account ' +
+          TAccountComp.AccountNumberToAccountTxtNumber(account.account) + ': ' + errors);
+      end;
+      i := TWallet.Keys.IndexOfAccountKey(account.accountInfo.accountKey);
+      if i < 0 then
+      begin
+        raise Exception.Create('Sender account private key not found in Wallet');
+      end;
+
+      wk := TWallet.Keys.Key[i];
+      dooperation := True;
+      // Default fee
+      if account.balance > uint64(Model.Fee.DefaultFee) then
+        _fee := Model.Fee.DefaultFee
+      else
+        _fee := account.balance;
+
+      if not UpdateOpChangeKey(account, signerAccount, _newOwnerPublicKey, errors) then
+      begin
+        raise Exception.Create(errors);
+      end;
+      if _V2 then
+      begin
+        // must ensure is Signer account last if included in sender accounts (not necessarily ordered enumeration)
+        if (iAcc < Length(Model.WIZChangeKey.SelectedAccounts) - 1) and
+          (account.account = signerAccount.account) then
+        begin
+          TArrayTool<TAccount>.Swap(Model.WIZChangeKey.SelectedAccounts, iAcc,
+            Length(Model.WIZChangeKey.SelectedAccounts) - 1); // ensure signer account processed last
+          // TArrayTool_internal<Cardinal>.Swap(_senderAccounts, iAcc, Length(_senderAccounts) - 1);
+          goto loop_start; // TODO: remove ugly hack with refactoring!
+        end;
+
+        // Maintain correct signer fee distribution
+        if uint64(_totalSignerFee) >= signerAccount.balance then
+          _fee := 0
+        else if signerAccount.balance - uint64(_totalSignerFee) >
+          uint64(Model.Fee.DefaultFee) then
+          _fee := Model.Fee.DefaultFee
+        else
+          _fee := signerAccount.balance - uint64(_totalSignerFee);
+        op := TOpChangeKeySigned.Create(signerAccount.account,
+          signerAccount.n_operation + _signer_n_ops + 1, account.account,
+          wk.PrivateKey, _newOwnerPublicKey, _fee, Model.Payload.EncodedBytes);
+        Inc(_signer_n_ops);
+        Inc(_totalSignerFee, _fee);
+      end
+      else
+      begin
+        op := TOpChangeKey.Create(account.account, account.n_operation +
+          1, account.account, wk.PrivateKey, _newOwnerPublicKey, _fee, Model.Payload.EncodedBytes);
+      end;
+      Inc(_totalfee, _fee);
+      operationstxt :=
+        'Change private key to ' + TAccountComp.GetECInfoTxt(
+        _newOwnerPublicKey.EC_OpenSSL_NID);
+
+      if Assigned(op) and (dooperation) then
+      begin
+        ops.AddOperationToHashTree(op);
+        if operation_to_string <> '' then
+          operation_to_string := operation_to_string + #10;
+        operation_to_string := operation_to_string + op.ToString;
+      end;
+      FreeAndNil(op);
+    end;
+
+    if (ops.OperationsCount = 0) then
+      raise Exception.Create('No valid operation to execute');
+
+    if (Length(Model.WIZChangeKey.SelectedAccounts) > 1) then
+    begin
+      auxs := '';
+      if Application.MessageBox(
+        PChar('Execute ' + IntToStr(Length(Model.WIZChangeKey.SelectedAccounts)) +
+        ' operations?' + #10 + 'Operation: ' + operationstxt + #10 +
+        auxs + 'Total fee: ' + TAccountComp.FormatMoney(_totalfee) +
+        #10 + #10 + 'Note: This operation will be transmitted to the network!'),
+        PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+        idYes then
+      begin
+        Exit;
+      end;
+    end
+    else
+    begin
+      if Application.MessageBox(PChar('Execute this operation:' + #10 +
+        #10 + operation_to_string + #10 + #10 +
+        'Note: This operation will be transmitted to the network!'),
+        PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <> idYes then
+      begin
+        Exit;
+      end;
+    end;
+    i := TNode.Node.AddOperations(nil, ops, nil, errors);
+    if (i = ops.OperationsCount) then
+    begin
+      operationstxt := 'Successfully executed ' + IntToStr(i) +
+        ' operations!' + #10 + #10 + operation_to_string;
+      if i > 1 then
+      begin
+
+        ShowMessage(operationstxt);
+      end
+      else
+      begin
+        Application.MessageBox(
+          PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
+          #10 + #10 + operation_to_string),
+          PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
+      end;
+
+    end
+    else if (i > 0) then
+    begin
+      operationstxt := 'One or more of your operations has not been executed:' +
+        #10 + 'Errors:' + #10 + errors + #10 + #10 +
+        'Total successfully executed operations: ' + IntToStr(i);
+
+      ShowMessage(operationstxt);
+    end
+    else
+    begin
+      raise Exception.Create(errors);
+    end;
+
+
+  finally
+    ops.Free;
+  end;
+
+end;
+
+constructor TWIZChangeKeyWizard.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner, [TWIZChangeKey_Start,
+    TWIZChangeKey_Confirmation]);
+  TitleText := 'Transfer Account';
+  FinishText := 'Transfer Account';
+end;
+
+function TWIZChangeKeyWizard.DetermineHasNext: boolean;
+begin
+  Result := not (CurrentScreen is TWIZChangeKey_Confirmation);
+end;
+
+function TWIZChangeKeyWizard.DetermineHasPrevious: boolean;
+begin
+  Result := inherited DetermineHasPrevious;
+end;
+
+function TWIZChangeKeyWizard.FinishRequested(out message: ansistring): boolean;
+begin
+  // Execute the Transfer Account Action here
+  try
+    Result := True;
+    WIZChangeKeyOwnership();
+  except
+    On E: Exception do
+    begin
+      Result := False;
+      message := E.ToString;
+    end;
+  end;
+end;
+
+function TWIZChangeKeyWizard.CancelRequested(out message: ansistring): boolean;
+begin
+  Result := True;
+end;
+
+end.

+ 1 - 1
src/gui/wizards/operations/UWIZEnlistAccountForSale_Start.lfm

@@ -3,10 +3,10 @@ object WIZEnlistAccountForSale_Start: TWIZEnlistAccountForSale_Start
   Height = 253
   Height = 253
   Top = 0
   Top = 0
   Width = 429
   Width = 429
+  ActiveControl = rbPublicSale
   Caption = 'WIZEnlistAccountForSale_Start'
   Caption = 'WIZEnlistAccountForSale_Start'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
   Visible = False
   Visible = False
   object Label1: TLabel
   object Label1: TLabel
     Left = 24
     Left = 24

+ 5 - 5
src/gui/wizards/operations/UWIZFeeOverride.lfm

@@ -55,20 +55,20 @@ object WIZFeeOverride: TWIZFeeOverride
       ParentColor = False
       ParentColor = False
       ParentFont = False
       ParentFont = False
     end
     end
-    object lbltotalfee: TLabel
+    object lblestimatedfee: TLabel
       Left = 11
       Left = 11
       Height = 15
       Height = 15
       Top = 66
       Top = 66
-      Width = 162
-      Caption = 'Total Fee For All Transcations:'
+      Width = 190
+      Caption = 'Estimated Fee For All Transcations:'
       Font.Style = [fsBold]
       Font.Style = [fsBold]
       ParentColor = False
       ParentColor = False
       ParentFont = False
       ParentFont = False
     end
     end
     object lblTotalFeeValue: TLabel
     object lblTotalFeeValue: TLabel
-      Left = 192
+      Left = 208
       Height = 15
       Height = 15
-      Top = 64
+      Top = 66
       Width = 28
       Width = 28
       Caption = 'xxxx'
       Caption = 'xxxx'
       Font.Style = [fsBold]
       Font.Style = [fsBold]

+ 5 - 7
src/gui/wizards/operations/UWIZFeeOverride.pas

@@ -18,7 +18,7 @@ interface
 uses
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
   ExtCtrls, Buttons, Spin, UCommon, UCommon.Collections, UWallet,
   ExtCtrls, Buttons, Spin, UCommon, UCommon.Collections, UWallet,
-  UFRMAccountSelect, UNode, UWizard, UWIZSendPASC, UWIZPayloadOverride, UWIZSelectSignerOverride, UWIZSendPASC_Confirmation, UWIZModels;
+  UFRMAccountSelect, UNode, UWizard, UWIZPayloadOverride, UWIZSelectSignerOverride, UWIZModels;
 
 
 type
 type
 
 
@@ -27,7 +27,7 @@ type
   TWIZFeeOverride = class(TWizardForm<TWIZOperationsModel>)
   TWIZFeeOverride = class(TWizardForm<TWIZOperationsModel>)
     fseFee: TFloatSpinEdit;
     fseFee: TFloatSpinEdit;
     gbTransactionFee: TGroupBox;
     gbTransactionFee: TGroupBox;
-    lbltotalfee: TLabel;
+    lblestimatedfee: TLabel;
     lblPASC: TLabel;
     lblPASC: TLabel;
     lblNote1: TLabel;
     lblNote1: TLabel;
     lblNote2: TLabel;
     lblNote2: TLabel;
@@ -58,7 +58,7 @@ var
 begin
 begin
   TAccountComp.TxtToMoney(Trim(fseFee.ValueToStr(fseFee.Value)), opfee);
   TAccountComp.TxtToMoney(Trim(fseFee.ValueToStr(fseFee.Value)), opfee);
   lblTotalFeeValue.Caption := Format('%s PASC', [TAccountComp.FormatMoney(opfee *
   lblTotalFeeValue.Caption := Format('%s PASC', [TAccountComp.FormatMoney(opfee *
-    Length(Model.SendPASC.SelectedAccounts))]);
+    Length(Model.Account.SelectedAccounts))]);
 end;
 end;
 
 
 procedure TWIZFeeOverride.fseFeeChange(Sender: TObject);
 procedure TWIZFeeOverride.fseFeeChange(Sender: TObject);
@@ -77,13 +77,11 @@ begin
     Model.Fee.SingleOperationFee);
     Model.Fee.SingleOperationFee);
   if Model.Payload.HasPayload then
   if Model.Payload.HasPayload then
   begin
   begin
-    UpdatePath(ptReplaceAllNext, [TWIZPayloadOverride,
-      TWIZSendPASC_Confirmation]);
+    UpdatePath(ptInject, [TWIZPayloadOverride]);
   end
   end
   else
   else
   begin
   begin
-    UpdatePath(ptReplaceAllNext, [TWIZSelectSignerOverride,
-      TWIZSendPASC_Confirmation]);
+  UpdatePath(ptInject, [TWIZSelectSignerOverride]);
   end;
   end;
 end;
 end;
 
 

+ 2 - 3
src/gui/wizards/operations/UWIZPayloadContentOverride.pas

@@ -18,7 +18,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, UWIZSelectSignerOverride, UWIZSendPASC_Confirmation, UWIZModels;
+  UWizard, UWIZSelectSignerOverride, UWIZModels;
 
 
 type
 type
 
 
@@ -46,8 +46,7 @@ uses
 procedure TWIZPayloadContentOverride.OnNext;
 procedure TWIZPayloadContentOverride.OnNext;
 begin
 begin
   Model.Payload.Content := mmoPayload.Lines.Text;
   Model.Payload.Content := mmoPayload.Lines.Text;
-   UpdatePath(ptReplaceAllNext, [TWIZSelectSignerOverride,
-      TWIZSendPASC_Confirmation]);
+   UpdatePath(ptInject, [TWIZSelectSignerOverride]);
 end;
 end;
 
 
 end.
 end.

+ 1 - 0
src/gui/wizards/operations/UWIZPayloadOverride.lfm

@@ -7,6 +7,7 @@ object WIZPayloadOverride: TWIZPayloadOverride
   Caption = 'Form1'
   Caption = 'Form1'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
+  LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
   object grpPayload: TGroupBox
   object grpPayload: TGroupBox
     Left = 8
     Left = 8

+ 3 - 5
src/gui/wizards/operations/UWIZPayloadOverride.pas

@@ -18,7 +18,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, UWIZPayloadContentOverride, UWIZPayloadPasswordOverride, UWIZSendPASC_Confirmation, UWIZModels;
+  UWizard, UWIZPayloadContentOverride, UWIZPayloadPasswordOverride, UWIZModels;
 
 
 type
 type
 
 
@@ -75,13 +75,11 @@ begin
   case Model.Payload.Mode of
   case Model.Payload.Mode of
     akaEncryptWithPassword:
     akaEncryptWithPassword:
     begin
     begin
-      UpdatePath(ptReplaceAllNext, [TWIZPayloadPasswordOverride,
-        TWIZSendPASC_Confirmation]);
+      UpdatePath(ptInject, [TWIZPayloadPasswordOverride]);
     end
     end
     else
     else
     begin
     begin
-      UpdatePath(ptReplaceAllNext, [TWIZPayloadContentOverride,
-        TWIZSendPASC_Confirmation]);
+      UpdatePath(ptInject, [TWIZPayloadContentOverride]);
     end;
     end;
   end;
   end;
 end;
 end;

+ 1 - 1
src/gui/wizards/operations/UWIZPayloadPasswordOverride.lfm

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

+ 2 - 3
src/gui/wizards/operations/UWIZPayloadPasswordOverride.pas

@@ -18,7 +18,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, UWIZSelectSignerOverride, UWIZSendPASC_Confirmation, UWIZModels;
+  UWizard, UWIZSelectSignerOverride, UWIZModels;
 
 
 type
 type
 
 
@@ -48,8 +48,7 @@ uses
 procedure TWIZPayloadPasswordOverride.OnNext;
 procedure TWIZPayloadPasswordOverride.OnNext;
 begin
 begin
   Model.Payload.Password := edtPassword.Text;
   Model.Payload.Password := edtPassword.Text;
-  UpdatePath(ptReplaceAllNext, [TWIZSelectSignerOverride,
-    TWIZSendPASC_Confirmation]);
+   UpdatePath(ptInject, [TWIZSelectSignerOverride]);
 end;
 end;
 
 
 function TWIZPayloadPasswordOverride.Validate(out message: ansistring): boolean;
 function TWIZPayloadPasswordOverride.Validate(out message: ansistring): boolean;

+ 7 - 9
src/gui/wizards/operations/UWIZSelectSignerOverride.pas

@@ -18,7 +18,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, UWallet,
   ExtCtrls, Buttons, UCommon, UCommon.Collections, UWallet,
-  UFRMAccountSelect, UNode, UWizard, UWIZSendPASC, UWIZSendPASC_Confirmation, UWIZModels;
+  UFRMAccountSelect, UNode, UWizard, UWIZModels;
 
 
 type
 type
 
 
@@ -33,8 +33,6 @@ type
     rbSecondary: TRadioButton;
     rbSecondary: TRadioButton;
     procedure cbSignerAccountChange(Sender: TObject);
     procedure cbSignerAccountChange(Sender: TObject);
 
 
-
-
   public
   public
     procedure OnPresent; override;
     procedure OnPresent; override;
     procedure OnNext; override;
     procedure OnNext; override;
@@ -62,7 +60,7 @@ begin
   begin
   begin
     lblBalance.Font.Color := clGreen;
     lblBalance.Font.Color := clGreen;
     lblBalance.Caption := Format('%s PASC',
     lblBalance.Caption := Format('%s PASC',
-      [TAccountComp.FormatMoney(Model.SendPASC.SelectedAccounts[PtrInt(
+      [TAccountComp.FormatMoney(Model.Signer.SignerCandidates[PtrInt(
       cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])].Balance)]);
       cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])].Balance)]);
   end;
   end;
 end;
 end;
@@ -83,23 +81,23 @@ begin
   try
   try
     cbSignerAccount.Items.Clear;
     cbSignerAccount.Items.Clear;
     cbSignerAccount.Items.Add('Select Signer Account');
     cbSignerAccount.Items.Add('Select Signer Account');
-    for i := Low(Model.SendPASC.SelectedAccounts) to High(Model.SendPASC.SelectedAccounts) do
+    for i := Low(Model.Signer.SignerCandidates) to High(Model.Signer.SignerCandidates) do
     begin
     begin
-      acc := Model.SendPASC.SelectedAccounts[i];
+      acc := Model.Signer.SignerCandidates[i];
       accNumberwithChecksum := GetAccNoWithChecksum(acc.account);
       accNumberwithChecksum := GetAccNoWithChecksum(acc.account);
       cbSignerAccount.Items.AddObject(accNumberwithChecksum, TObject(i));
       cbSignerAccount.Items.AddObject(accNumberwithChecksum, TObject(i));
     end;
     end;
   finally
   finally
     cbSignerAccount.Items.EndUpdate;
     cbSignerAccount.Items.EndUpdate;
   end;
   end;
-  cbSignerAccount.ItemIndex := Model.SendPASC.SelectedIndex;
+  cbSignerAccount.ItemIndex := Model.Signer.SelectedIndex;
   cbSignerAccountChange(Self);
   cbSignerAccountChange(Self);
 end;
 end;
 
 
 procedure TWIZSelectSignerOverride.OnNext;
 procedure TWIZSelectSignerOverride.OnNext;
 begin
 begin
-  Model.SendPASC.SelectedIndex := cbSignerAccount.ItemIndex;
-  Model.Signer.SignerAccount := Model.SendPASC.SelectedAccounts[PtrInt(
+  Model.Signer.SelectedIndex := cbSignerAccount.ItemIndex;
+  Model.Signer.SignerAccount := Model.Signer.SignerCandidates[PtrInt(
     cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])];
     cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])];
   if rbPrimary.Checked then
   if rbPrimary.Checked then
   begin
   begin

+ 48 - 42
src/gui/wizards/operations/UWIZSendPASC.pas

@@ -2,13 +2,14 @@ unit UWIZSendPASC;
 
 
 {$mode delphi}
 {$mode delphi}
 
 
-{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+{ Copyright (c) 2018 Sphere 10 Software (http://www.sphere10.com/)
 
 
   Distributed under the MIT software license, see the accompanying file LICENSE
   Distributed under the MIT software license, see the accompanying file LICENSE
   or visit http://www.opensource.org/licenses/mit-license.php.
   or visit http://www.opensource.org/licenses/mit-license.php.
 
 
   Acknowledgements:
   Acknowledgements:
-    Herman Schoenfeld <[email protected]>: added grid-based layout
+  Ugochukwu Mmaduekwe - main developer
+  Herman Schoenfeld - designer <[email protected]>: added grid-based layout
 }
 }
 
 
 interface
 interface
@@ -22,11 +23,9 @@ type
 
 
   TWIZSendPASCWizard = class(TWizard<TWIZOperationsModel>)
   TWIZSendPASCWizard = class(TWizard<TWIZOperationsModel>)
   private
   private
-    function UpdatePayload(const SenderAccount: TAccount;
-      var errors: string): boolean;
+    function UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
     function UpdateOperationOptions(var errors: string): boolean;
     function UpdateOperationOptions(var errors: string): boolean;
-    function UpdateOpTransaction(const SenderAccount: TAccount;
-      var DestAccount: TAccount; var amount: int64; var errors: string): boolean;
+    function UpdateOpTransaction(const SenderAccount: TAccount; var DestAccount: TAccount; var amount: int64; var errors: string): boolean;
     procedure SendPASC();
     procedure SendPASC();
   public
   public
     constructor Create(AOwner: TComponent); override;
     constructor Create(AOwner: TComponent); override;
@@ -67,7 +66,7 @@ begin
     Exit;
     Exit;
   end;
   end;
 
 
-  if Length(Model.SendPASC.SelectedAccounts) = 0 then
+  if Length(Model.Account.SelectedAccounts) = 0 then
   begin
   begin
     errors := 'No sender account';
     errors := 'No sender account';
     Exit;
     Exit;
@@ -75,9 +74,9 @@ begin
   else
   else
   begin
   begin
 
 
-    for iAcc := Low(Model.SendPASC.SelectedAccounts) to High(Model.SendPASC.SelectedAccounts) do
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
     begin
     begin
-      sender_account := Model.SendPASC.SelectedAccounts[iAcc];
+      sender_account := Model.Account.SelectedAccounts[iAcc];
       iWallet := TWallet.Keys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
       iWallet := TWallet.Keys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
       if (iWallet < 0) then
       if (iWallet < 0) then
       begin
       begin
@@ -105,12 +104,11 @@ begin
     end;
     end;
   end;
   end;
 
 
-  Result := UpdateOpTransaction(Model.SendPASC.SelectedAccounts[0], dest_account, amount, errors);
+  Result := UpdateOpTransaction(Model.Account.SelectedAccounts[0], dest_account, amount, errors);
   UpdatePayload(sender_account, e);
   UpdatePayload(sender_account, e);
 end;
 end;
 
 
-function TWIZSendPASCWizard.UpdateOpTransaction(const SenderAccount: TAccount;
-  var DestAccount: TAccount; var amount: int64; var errors: string): boolean;
+function TWIZSendPASCWizard.UpdateOpTransaction(const SenderAccount: TAccount; var DestAccount: TAccount; var amount: int64; var errors: string): boolean;
 var
 var
   c: cardinal;
   c: cardinal;
 begin
 begin
@@ -119,13 +117,16 @@ begin
 
 
   DestAccount := Model.SendPASC.DestinationAccount;
   DestAccount := Model.SendPASC.DestinationAccount;
 
 
-  if Length(Model.SendPASC.SelectedAccounts) = 1 then
-  begin
-    amount := Model.SendPASC.SingleAmountToSend;
-  end
-  else
-  begin
-    amount := 0; // ALL BALANCE
+  case Model.SendPASC.SendPASCMode of
+    akaAllBalance:
+    begin
+      amount := 0; // ALL BALANCE
+    end;
+
+    akaSpecifiedAmount:
+    begin
+      amount := Model.SendPASC.SingleAmountToSend;
+    end;
   end;
   end;
 
 
   if DestAccount.account = SenderAccount.account then
   if DestAccount.account = SenderAccount.account then
@@ -134,14 +135,17 @@ begin
     Exit;
     Exit;
   end;
   end;
 
 
-  if (Length(Model.SendPASC.SelectedAccounts) = 1) then
-  begin
-    if (SenderAccount.balance < (amount + Model.Fee.SingleOperationFee)) then
+  case Model.SendPASC.SendPASCMode of
+    akaSpecifiedAmount:
     begin
     begin
-      errors := 'Insufficient funds';
-      Exit;
+      if (SenderAccount.balance < (amount + Model.Fee.SingleOperationFee)) then
+      begin
+        errors := 'Insufficient funds';
+        Exit;
+      end;
     end;
     end;
   end;
   end;
+
   Result := True;
   Result := True;
 end;
 end;
 
 
@@ -170,10 +174,10 @@ begin
     _signer_n_ops := 0;
     _signer_n_ops := 0;
     operationstxt := '';
     operationstxt := '';
     operation_to_string := '';
     operation_to_string := '';
-    for iAcc := Low(Model.SendPASC.SelectedAccounts) to High(Model.SendPASC.SelectedAccounts) do
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
     begin
     begin
       op := nil;
       op := nil;
-      account := Model.SendPASC.SelectedAccounts[iAcc];
+      account := Model.Account.SelectedAccounts[iAcc];
       if not UpdatePayload(account, errors) then
       if not UpdatePayload(account, errors) then
       begin
       begin
         raise Exception.Create('Error encoding payload of sender account ' +
         raise Exception.Create('Error encoding payload of sender account ' +
@@ -195,27 +199,30 @@ begin
 
 
       if not UpdateOpTransaction(account, destAccount, _amount, errors) then
       if not UpdateOpTransaction(account, destAccount, _amount, errors) then
         raise Exception.Create(errors);
         raise Exception.Create(errors);
-      if Length(Model.SendPASC.SelectedAccounts) > 1 then
+
+      if account.balance > 0 then
       begin
       begin
-        if account.balance > 0 then
+        if account.balance > Model.Fee.SingleOperationFee then
         begin
         begin
-          if account.balance > Model.Fee.SingleOperationFee then
-          begin
-            _amount := account.balance - Model.Fee.SingleOperationFee;
-            _fee := Model.Fee.SingleOperationFee;
-          end
-          else
-          begin
-            _amount := account.balance;
-            _fee := 0;
+          case Model.SendPASC.SendPASCMode of
+            akaAllBalance:
+            begin
+              _amount := account.balance - Model.Fee.SingleOperationFee;
+              _fee := Model.Fee.SingleOperationFee;
+            end;
           end;
           end;
         end
         end
         else
         else
-          dooperation := False;
+        begin
+          _amount := account.balance;
+          _fee := 0;
+        end;
       end
       end
       else
       else
       begin
       begin
+        dooperation := False;
       end;
       end;
+
       if dooperation then
       if dooperation then
       begin
       begin
         op := TOpTransaction.CreateTransaction(
         op := TOpTransaction.CreateTransaction(
@@ -240,12 +247,12 @@ begin
     if (ops.OperationsCount = 0) then
     if (ops.OperationsCount = 0) then
       raise Exception.Create('No valid operation to execute');
       raise Exception.Create('No valid operation to execute');
 
 
-    if (Length(Model.SendPASC.SelectedAccounts) > 1) then
+    if (Length(Model.Account.SelectedAccounts) > 1) then
     begin
     begin
       auxs := 'Total amount that dest will receive: ' + TAccountComp.FormatMoney(
       auxs := 'Total amount that dest will receive: ' + TAccountComp.FormatMoney(
         _totalamount) + #10;
         _totalamount) + #10;
       if Application.MessageBox(
       if Application.MessageBox(
-        PChar('Execute ' + IntToStr(Length(Model.SendPASC.SelectedAccounts)) +
+        PChar('Execute ' + IntToStr(Length(Model.Account.SelectedAccounts)) +
         ' operations?' + #10 + 'Operation: ' + operationstxt + #10 +
         ' operations?' + #10 + 'Operation: ' + operationstxt + #10 +
         auxs + 'Total fee: ' + TAccountComp.FormatMoney(_totalfee) +
         auxs + 'Total fee: ' + TAccountComp.FormatMoney(_totalfee) +
         #10 + #10 + 'Note: This operation will be transmitted to the network!'),
         #10 + #10 + 'Note: This operation will be transmitted to the network!'),
@@ -316,8 +323,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TWIZSendPASCWizard.UpdatePayload(const SenderAccount: TAccount;
-  var errors: string): boolean;
+function TWIZSendPASCWizard.UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
 var
 var
   valid: boolean;
   valid: boolean;
   payload_encrypted, payload_u: string;
   payload_encrypted, payload_u: string;

+ 1 - 1
src/gui/wizards/operations/UWIZSendPASC_ConfirmSender.lfm

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

+ 40 - 24
src/gui/wizards/operations/UWIZSendPASC_ConfirmSender.pas

@@ -27,10 +27,11 @@ type
     gpSender: TGroupBox;
     gpSender: TGroupBox;
     paGrid: TPanel;
     paGrid: TPanel;
   private
   private
-    FSendersGrid : TVisualGrid;
+    FSendersGrid: TVisualGrid;
   public
   public
     procedure OnPresent; override;
     procedure OnPresent; override;
     procedure OnNext; override;
     procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
   end;
   end;
 
 
 
 
@@ -39,56 +40,58 @@ implementation
 
 
 {$R *.lfm}
 {$R *.lfm}
 
 
-uses UAccounts, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+uses UAccounts, UCoreUtils, UDataSources, UCommon, UCommon.UI, Generics.Collections;
 
 
 type
 type
 
 
   { TAccountSenderDataSource }
   { TAccountSenderDataSource }
 
 
   TAccountSenderDataSource = class(TAccountsDataSourceBase)
   TAccountSenderDataSource = class(TAccountsDataSourceBase)
-    private
-      FModel : TWIZOperationsModel.TSendPASCModel;
-    public
-      property Model : TWIZOperationsModel.TSendPASCModel read FModel write FModel;
-      procedure FetchAll(const AContainer : TList<TAccount>); override;
+  private
+    FModel: TWIZOperationsModel;
+  public
+    property Model: TWIZOperationsModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
   end;
   end;
 
 
 { TWIZSendPASC_ConfirmSender }
 { TWIZSendPASC_ConfirmSender }
 
 
 procedure TWIZSendPASC_ConfirmSender.OnPresent;
 procedure TWIZSendPASC_ConfirmSender.OnPresent;
 var
 var
-  data : TAccountSenderDataSource;
+  Data: TAccountSenderDataSource;
 begin
 begin
   FSendersGrid := TVisualGrid.Create(Self);
   FSendersGrid := TVisualGrid.Create(Self);
-  FSendersGrid.CanSearch:= False;
+  FSendersGrid.CanSearch := False;
   FSendersGrid.SortMode := smMultiColumn;
   FSendersGrid.SortMode := smMultiColumn;
   FSendersGrid.FetchDataInThread := False;
   FSendersGrid.FetchDataInThread := False;
   FSendersGrid.AutoPageSize := True;
   FSendersGrid.AutoPageSize := True;
   FSendersGrid.SelectionType := stNone;
   FSendersGrid.SelectionType := stNone;
   FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
   FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
-  with FSendersGrid.AddColumn('Account') do begin
-    StretchedToFill := true;
+  with FSendersGrid.AddColumn('Account') do
+  begin
+    StretchedToFill := True;
     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 FSendersGrid.AddColumn('Balance') do begin
+  with FSendersGrid.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;
-  data := TAccountSenderDataSource.Create(FSendersGrid);
-  data.Model := Model.SendPASC;
-  FSendersGrid.DataSource := data;
+  Data := TAccountSenderDataSource.Create(FSendersGrid);
+  Data.Model := Model;
+  FSendersGrid.DataSource := Data;
   paGrid.AddControlDockCenter(FSendersGrid);
   paGrid.AddControlDockCenter(FSendersGrid);
 end;
 end;
 
 
@@ -97,17 +100,30 @@ begin
   UpdatePath(ptReplaceAllNext, [TWIZSendPASC_EnterRecipient, TWIZSendPASC_Confirmation]);
   UpdatePath(ptReplaceAllNext, [TWIZSendPASC_EnterRecipient, TWIZSendPASC_Confirmation]);
 end;
 end;
 
 
+function TWIZSendPASC_ConfirmSender.Validate(out message: ansistring): boolean;
+begin
+  Result := True;
+  // get signer accounts from selected accounts
+  Model.Signer.SignerCandidates := TCoreTool.GetSignerCandidates(Length(Model.Account.SelectedAccounts), Model.Account.SelectedAccounts);
+
+  if Length(Model.Signer.SignerCandidates) < 1 then
+  begin
+    Result := False;
+    message := 'no valid signer account was found.';
+  end;
+
+end;
+
 { TAccountSenderDataSource }
 { TAccountSenderDataSource }
 
 
-procedure TAccountSenderDataSource.FetchAll(const AContainer : TList<TAccount>);
+procedure TAccountSenderDataSource.FetchAll(const AContainer: TList<TAccount>);
 var
 var
-  i: Integer;
+  i: integer;
 begin
 begin
-  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
   begin
   begin
-    AContainer.Add( Model.SelectedAccounts[i] );
+    AContainer.Add(Model.Account.SelectedAccounts[i]);
   end;
   end;
 end;
 end;
 
 
 end.
 end.
-

+ 43 - 39
src/gui/wizards/operations/UWIZSendPASC_Confirmation.pas

@@ -31,7 +31,7 @@ type
     lblSgnAcc: TLabel;
     lblSgnAcc: TLabel;
     paGrid: TPanel;
     paGrid: TPanel;
   private
   private
-    FSendersGrid : TVisualGrid;
+    FSendersGrid: TVisualGrid;
   public
   public
     procedure OnPresent; override;
     procedure OnPresent; override;
   end;
   end;
@@ -48,97 +48,101 @@ type
   { TAccountSenderDataSource }
   { TAccountSenderDataSource }
 
 
   TAccountSenderDataSource = class(TAccountsDataSourceBase)
   TAccountSenderDataSource = class(TAccountsDataSourceBase)
-    private
-      FModel : TWIZOperationsModel;
-    protected
-      function GetColumns : TDataColumns; override;
-    public
-      property Model : TWIZOperationsModel read FModel write FModel;
-      procedure FetchAll(const AContainer : TList<TAccount>); override;
-      function GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant; override;
+  private
+    FModel: TWIZOperationsModel;
+  protected
+    function GetColumns: TDataColumns; override;
+  public
+    property Model: TWIZOperationsModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
+    function GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant; override;
   end;
   end;
 
 
 { TWIZSendPASC_Confirmation }
 { TWIZSendPASC_Confirmation }
 
 
 procedure TWIZSendPASC_Confirmation.OnPresent;
 procedure TWIZSendPASC_Confirmation.OnPresent;
 var
 var
-  data : TAccountSenderDataSource;
+  Data: TAccountSenderDataSource;
 begin
 begin
   FSendersGrid := TVisualGrid.Create(Self);
   FSendersGrid := TVisualGrid.Create(Self);
-  FSendersGrid.CanSearch:= False;
+  FSendersGrid.CanSearch := False;
   FSendersGrid.SortMode := smMultiColumn;
   FSendersGrid.SortMode := smMultiColumn;
   FSendersGrid.FetchDataInThread := False;
   FSendersGrid.FetchDataInThread := False;
   FSendersGrid.AutoPageSize := True;
   FSendersGrid.AutoPageSize := True;
   FSendersGrid.SelectionType := stNone;
   FSendersGrid.SelectionType := stNone;
   FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
   FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
-  with FSendersGrid.AddColumn('Sender') do begin
+  with FSendersGrid.AddColumn('Sender') do
+  begin
     Binding := 'SenderAccount';
     Binding := 'SenderAccount';
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
     Width := 100;
     Width := 100;
     HeaderFontStyles := [fsBold];
     HeaderFontStyles := [fsBold];
     DataFontStyles := [fsBold];
     DataFontStyles := [fsBold];
   end;
   end;
-  with FSendersGrid.AddColumn('Balance') do begin
+  with FSendersGrid.AddColumn('Balance') do
+  begin
     Filters := SORTABLE_NUMERIC_FILTER;
     Filters := SORTABLE_NUMERIC_FILTER;
     Width := 100;
     Width := 100;
     Renderer := TCellRenderers.PASC;
     Renderer := TCellRenderers.PASC;
   end;
   end;
-  with FSendersGrid.AddColumn('Amount To Send') do begin
+  with FSendersGrid.AddColumn('Amount To Send') do
+  begin
     Binding := 'AmountToSend';
     Binding := 'AmountToSend';
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
     Width := 100;
     Width := 100;
   end;
   end;
-  with FSendersGrid.AddColumn('Fee') do begin
+  with FSendersGrid.AddColumn('Fee') do
+  begin
     Filters := SORTABLE_TEXT_FILTER;
     Filters := SORTABLE_TEXT_FILTER;
     Width := 100;
     Width := 100;
   end;
   end;
 
 
-   data := TAccountSenderDataSource.Create(FSendersGrid);
-   data.Model := Model;
-   FSendersGrid.DataSource := data;
-   paGrid.AddControlDockCenter(FSendersGrid);
-   lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.Signer.SignerAccount.account);
-   lblDestAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.SendPASC.DestinationAccount.account);
+  Data := TAccountSenderDataSource.Create(FSendersGrid);
+  Data.Model := Model;
+  FSendersGrid.DataSource := Data;
+  paGrid.AddControlDockCenter(FSendersGrid);
+  lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.Signer.SignerAccount.account);
+  lblDestAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.SendPASC.DestinationAccount.account);
 end;
 end;
 
 
 { TAccountSenderDataSource }
 { TAccountSenderDataSource }
 
 
-function TAccountSenderDataSource.GetColumns : TDataColumns;
+function TAccountSenderDataSource.GetColumns: TDataColumns;
 begin
 begin
   Result := TDataColumns.Create(
   Result := TDataColumns.Create(
     TDataColumn.From('SenderAccount'),
     TDataColumn.From('SenderAccount'),
     TDataColumn.From('Balance'),
     TDataColumn.From('Balance'),
     TDataColumn.From('AmountToSend'),
     TDataColumn.From('AmountToSend'),
     TDataColumn.From('Fee')
     TDataColumn.From('Fee')
-  );
+    );
 end;
 end;
 
 
-function TAccountSenderDataSource.GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant;
+function TAccountSenderDataSource.GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant;
 var
 var
-  index : Integer;
+  index: integer;
 begin
 begin
-   if ABindingName = 'SenderAccount' then
-     Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
-   else if ABindingName = 'Balance' then
-     Result := TAccountComp.FormatMoney(AItem.Balance)
-   else if ABindingName = 'AmountToSend' then
-     Result := TAccountComp.FormatMoney(Model.SendPASC.SingleAmountToSend)
-     else if ABindingName = 'Fee' then
-     Result := TAccountComp.FormatMoney(Model.Fee.SingleOperationFee)
-   else raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
+  if ABindingName = 'SenderAccount' then
+    Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
+  else if ABindingName = 'Balance' then
+    Result := TAccountComp.FormatMoney(AItem.Balance)
+  else if ABindingName = 'AmountToSend' then
+    Result := IIF(Model.SendPASC.SendPASCMode = akaAllBalance, 'ALL BALANCE', TAccountComp.FormatMoney(Model.SendPASC.SingleAmountToSend))
+  else if ABindingName = 'Fee' then
+    Result := TAccountComp.FormatMoney(Model.Fee.SingleOperationFee)
+  else
+    raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
 end;
 end;
 
 
 
 
-procedure TAccountSenderDataSource.FetchAll(const AContainer : TList<TAccount>);
+procedure TAccountSenderDataSource.FetchAll(const AContainer: TList<TAccount>);
 var
 var
-  i: Integer;
+  i: integer;
 begin
 begin
-  for i := Low(Model.SendPASC.SelectedAccounts) to High(Model.SendPASC.SelectedAccounts) do
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
   begin
   begin
-    AContainer.Add( Model.SendPASC.SelectedAccounts[i] );
+    AContainer.Add(Model.Account.SelectedAccounts[i]);
   end;
   end;
 end;
 end;
 
 
 
 
 end.
 end.
-

+ 3 - 1
src/gui/wizards/operations/UWIZSendPASC_EnterQuantity.pas

@@ -59,11 +59,13 @@ begin
   begin
   begin
     edtAmt.Text := 'ALL BALANCE';
     edtAmt.Text := 'ALL BALANCE';
     edtAmt.Enabled := False;
     edtAmt.Enabled := False;
+    Model.SendPASC.SendPASCMode := akaAllBalance;
   end
   end
   else
   else
   begin
   begin
     edtAmt.Text := TAccountComp.FormatMoney(0);
     edtAmt.Text := TAccountComp.FormatMoney(0);
     edtAmt.Enabled := True;
     edtAmt.Enabled := True;
+    Model.SendPASC.SendPASCMode := akaSpecifiedAmount;
   end;
   end;
 
 
   Model.Payload.HasPayload := IIF(chkAttachPayload.Checked, True, False);
   Model.Payload.HasPayload := IIF(chkAttachPayload.Checked, True, False);
@@ -77,7 +79,7 @@ end;
 
 
 procedure TWIZSendPASC_EnterQuantity.OnPresent;
 procedure TWIZSendPASC_EnterQuantity.OnPresent;
 begin
 begin
-  edtAmt.Text := TAccountComp.FormatMoney(0);
+  UpdateUI();
 end;
 end;
 
 
 procedure TWIZSendPASC_EnterQuantity.chkAttachPayloadChange(Sender: TObject);
 procedure TWIZSendPASC_EnterQuantity.chkAttachPayloadChange(Sender: TObject);

+ 1 - 0
src/gui/wizards/operations/UWIZSendPASC_EnterRecipient.lfm

@@ -7,6 +7,7 @@ object WIZSendPASC_EnterRecipient: TWIZSendPASC_EnterRecipient
   Caption = 'WIZSendPASC_EnterRecipient'
   Caption = 'WIZSendPASC_EnterRecipient'
   ClientHeight = 253
   ClientHeight = 253
   ClientWidth = 429
   ClientWidth = 429
+  LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
   object gbRecipient: TGroupBox
   object gbRecipient: TGroupBox
     Left = 16
     Left = 16

+ 1 - 1
src/gui/wizards/operations/UWIZSendPASC_EnterRecipient.pas

@@ -154,7 +154,7 @@ begin
   end;
   end;
 
 
   AccountNumbersWithChecksum :=
   AccountNumbersWithChecksum :=
-    TListTool<TAccount, string>.Transform(Model.SendPASC.SelectedAccounts, GetAccNoWithCheckSum);
+    TListTool<TAccount, string>.Transform(Model.Account.SelectedAccounts, GetAccNoWithCheckSum);
 
 
   if TArrayTool<string>.Contains(AccountNumbersWithChecksum, edtDestAcc.Text) then
   if TArrayTool<string>.Contains(AccountNumbersWithChecksum, edtDestAcc.Text) then
   begin
   begin

+ 0 - 19
src/gui/wizards/operations/UWIZSendPASC_FeeOverride.lfm

@@ -1,19 +0,0 @@
-object WIZFeeOverride: TWIZFeeOverride
-  Left = 0
-  Height = 253
-  Top = 0
-  Width = 429
-  Caption = 'WIZFeeOverride'
-  ClientHeight = 253
-  ClientWidth = 429
-  LCLVersion = '1.8.1.0'
-  Visible = False
-  object gbTransactionFee: TGroupBox
-    Left = 14
-    Height = 232
-    Top = 8
-    Width = 400
-    Caption = 'Transaction Fee'
-    TabOrder = 0
-  end
-end

+ 2 - 0
src/gui/wizards/operations/UWIZTransferAccount.pas

@@ -7,6 +7,8 @@ unit UWIZTransferAccount;
   Distributed under the MIT software license, see the accompanying file LICENSE
   Distributed under the MIT software license, see the accompanying file LICENSE
   or visit http://www.opensource.org/licenses/mit-license.php.
   or visit http://www.opensource.org/licenses/mit-license.php.
 
 
+  Acknowledgements:
+    Herman Schoenfeld <[email protected]>: added grid-based layout
 }
 }
 
 
 interface
 interface

+ 61 - 58
src/pascalcoin_wallet.lpi

@@ -33,7 +33,7 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item1>
       </Item1>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="101">
+    <Units Count="97">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -368,182 +368,185 @@
       <Unit68>
       <Unit68>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_EnterName.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_EnterName.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_EnterName"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit68>
       </Unit68>
       <Unit69>
       <Unit69>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_GenerateOrImport.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_GenerateOrImport.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_GenerateOrImport"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit69>
       </Unit69>
       <Unit70>
       <Unit70>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_ImportPrivKey.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_ImportPrivKey.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_ImportPrivKey"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit70>
       </Unit70>
       <Unit71>
       <Unit71>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_ImportPubKey.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_ImportPubKey.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_ImportPubKey"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit71>
       </Unit71>
       <Unit72>
       <Unit72>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_SelectEncryption.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_SelectEncryption.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_SelectEncryption"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit72>
       </Unit72>
       <Unit73>
       <Unit73>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_Start.pas"/>
         <Filename Value="gui\wizards\wallet\UWIZAddKey_Start.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_Start"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit73>
       </Unit73>
       <Unit74>
       <Unit74>
-        <Filename Value="gui\wizards\operations\UWIZChangeAccountPrivateKey.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit74>
       </Unit74>
       <Unit75>
       <Unit75>
-        <Filename Value="gui\wizards\operations\UWIZChangeAccountPrivateKey_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeAccountPrivateKey_Confirmation"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit75>
       </Unit75>
       <Unit76>
       <Unit76>
-        <Filename Value="gui\wizards\operations\UWIZChangeAccountPrivateKey_Start.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_List.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
       </Unit76>
       </Unit76>
       <Unit77>
       <Unit77>
-        <Filename Value="gui\wizards\operations\UWIZChangeAccountPrivateKey_Transaction.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_PrivateSaleConfig.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeAccountPrivateKey_Transaction"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit77>
       </Unit77>
       <Unit78>
       <Unit78>
-        <Filename Value="gui\wizards\operations\UWIZChangeAccountPrivateKey_TransactionPayload.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Start.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
       </Unit78>
       </Unit78>
       <Unit79>
       <Unit79>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Transaction.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZEnlistAccountForSale_Transaction"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit79>
       </Unit79>
       <Unit80>
       <Unit80>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_TransactionPayload.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
       </Unit80>
       </Unit80>
       <Unit81>
       <Unit81>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_List.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZFeeOverride.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZFeeOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit81>
       </Unit81>
       <Unit82>
       <Unit82>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_PrivateSaleConfig.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZPayloadContentOverride.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZPayloadContentOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit82>
       </Unit82>
       <Unit83>
       <Unit83>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Start.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZPayloadOverride.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZPayloadOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit83>
       </Unit83>
       <Unit84>
       <Unit84>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Transaction.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZPayloadPasswordOverride.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZEnlistAccountForSale_Transaction"/>
+        <ComponentName Value="WIZPayloadPasswordOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit84>
       </Unit84>
       <Unit85>
       <Unit85>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_TransactionPayload.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSelectSignerOverride.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSelectSignerOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit85>
       </Unit85>
       <Unit86>
       <Unit86>
-        <Filename Value="gui\wizards\operations\UWIZFeeOverride.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <HasResources Value="True"/>
       </Unit86>
       </Unit86>
       <Unit87>
       <Unit87>
-        <Filename Value="gui\wizards\operations\UWIZPayloadContentOverride.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZPayloadContentOverride"/>
+        <ComponentName Value="WIZSendPASC_Confirmation"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit87>
       </Unit87>
       <Unit88>
       <Unit88>
-        <Filename Value="gui\wizards\operations\UWIZPayloadOverride.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_ConfirmSender.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_ConfirmSender"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit88>
       </Unit88>
       <Unit89>
       <Unit89>
-        <Filename Value="gui\wizards\operations\UWIZPayloadPasswordOverride.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterQuantity.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZSendPASC_EnterQuantity"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit89>
       </Unit89>
       <Unit90>
       <Unit90>
-        <Filename Value="gui\wizards\operations\UWIZSelectSignerOverride.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterRecipient.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSelectSignerOverride"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit90>
       </Unit90>
       <Unit91>
       <Unit91>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit91>
       </Unit91>
       <Unit92>
       <Unit92>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectOption.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_Confirmation"/>
+        <ComponentName Value="WIZChangeKey_SelectOption"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit92>
       </Unit92>
       <Unit93>
       <Unit93>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_ConfirmSender.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_EnterKey.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZChangeKey_EnterKey"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit93>
       </Unit93>
       <Unit94>
       <Unit94>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterQuantity.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectKey.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_EnterQuantity"/>
+        <ComponentName Value="WIZChangeKey_SelectKey"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit94>
       </Unit94>
       <Unit95>
       <Unit95>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterRecipient.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_ConfirmAccount.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZChangeKey_ConfirmAccount"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit95>
       </Unit95>
       <Unit96>
       <Unit96>
-        <Filename Value="gui\wizards\operations\UWIZTransferAccount.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit96>
-      <Unit97>
-        <Filename Value="gui\wizards\operations\UWIZTransferAccount_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZTransferAccount_Confirmation"/>
+        <ComponentName Value="WIZChangeKey_Confirmation"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit97>
-      <Unit98>
-        <Filename Value="gui\wizards\operations\UWIZTransferAccount_Start.pas"/>
-        <IsPartOfProject Value="True"/>
-        <HasResources Value="True"/>
-      </Unit98>
-      <Unit99>
-        <Filename Value="gui\wizards\operations\UWIZTransferAccount_Transaction.pas"/>
-        <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZTransferAccount_Transaction"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
-      </Unit99>
-      <Unit100>
-        <Filename Value="gui\wizards\operations\UWIZTransferAccount_TransactionPayload.pas"/>
-        <IsPartOfProject Value="True"/>
-        <HasResources Value="True"/>
-      </Unit100>
+      </Unit96>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>