Browse Source

Merge downstream

Herman Schoenfeld 7 years ago
parent
commit
59bc44f1aa
32 changed files with 971 additions and 1051 deletions
  1. 18 2
      src/gui/UCTRLWallet.pas
  2. 19 2
      src/gui/wizards/UWIZModels.pas
  3. 1 0
      src/gui/wizards/operations/UWIZChangeKey_Confirmation.lfm
  4. 3 29
      src/gui/wizards/operations/UWIZChangeKey_Confirmation.pas
  5. 59 114
      src/gui/wizards/operations/UWIZEnlistAccountForSale.pas
  6. 4 4
      src/gui/wizards/operations/UWIZEnlistAccountForSale_ConfirmAccount.lfm
  7. 128 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_ConfirmAccount.pas
  8. 1 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_Confirmation.lfm
  9. 38 33
      src/gui/wizards/operations/UWIZEnlistAccountForSale_Confirmation.pas
  10. 36 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterLockingBlock.lfm
  11. 63 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterLockingBlock.pas
  12. 36 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterPublicKey.lfm
  13. 79 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterPublicKey.pas
  14. 52 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSaleAmount.lfm
  15. 118 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSaleAmount.pas
  16. 53 87
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSeller.lfm
  17. 159 0
      src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSeller.pas
  18. 0 141
      src/gui/wizards/operations/UWIZEnlistAccountForSale_List.pas
  19. 0 50
      src/gui/wizards/operations/UWIZEnlistAccountForSale_PrivateSaleConfig.lfm
  20. 0 92
      src/gui/wizards/operations/UWIZEnlistAccountForSale_PrivateSaleConfig.pas
  21. 3 3
      src/gui/wizards/operations/UWIZEnlistAccountForSale_SelectOption.lfm
  22. 11 14
      src/gui/wizards/operations/UWIZEnlistAccountForSale_SelectOption.pas
  23. 0 199
      src/gui/wizards/operations/UWIZEnlistAccountForSale_Transaction.pas
  24. 0 98
      src/gui/wizards/operations/UWIZEnlistAccountForSale_TransactionPayload.lfm
  25. 0 82
      src/gui/wizards/operations/UWIZEnlistAccountForSale_TransactionPayload.pas
  26. 1 0
      src/gui/wizards/operations/UWIZOperationFee_Custom.lfm
  27. 26 6
      src/gui/wizards/operations/UWIZOperationFee_Custom.pas
  28. 0 36
      src/gui/wizards/operations/UWIZOperationPayload_Encryption.lrs
  29. 1 0
      src/gui/wizards/operations/UWIZSendPASC.pas
  30. 1 0
      src/gui/wizards/operations/UWIZSendPASC_Confirmation.lfm
  31. 0 15
      src/gui/wizards/operations/UWIZSendPASC_Confirmation.pas
  32. 61 44
      src/pascalcoin_wallet.lpi

+ 18 - 2
src/gui/UCTRLWallet.pas

@@ -9,7 +9,7 @@ interface
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
   ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
-  UAccounts, UDataSources, UNode, UWIZSendPASC, UWIZChangeKey, UCoreObjects, UCoreUtils;
+  UAccounts, UDataSources, UNode, UCoreObjects, UCoreUtils, UWIZSendPASC, UWIZChangeKey, UWIZEnlistAccountForSale;
 
 type
 
@@ -675,8 +675,24 @@ begin
 end;
 
 procedure TCTRLWallet.miEnlistAccountsForSaleClick(Sender: TObject);
+var
+  Scoped: TDisposables;
+  wiz: TWIZEnlistAccountForSaleWizard;
+  model: TWIZOperationsModel;
+  AccountNumbersWithoutChecksum: TArray<cardinal>;
+
+   function GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
+  begin
+    Result := ARow.__KEY;
+  end;
+
+
 begin
- raise ENotImplemented.Create('not yet implemented.');
+  wiz := Scoped.AddObject(TWIZEnlistAccountForSaleWizard.Create(nil)) as TWIZEnlistAccountForSaleWizard;
+  model := TWIZOperationsModel.Create(wiz, omtEnlistAccountForSale);
+  AccountNumbersWithoutChecksum := TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNoWithoutChecksum);
+  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
+  wiz.Start(model);
 end;
 
 procedure TCTRLWallet.miDelistAccountsFromSaleClick(Sender: TObject);

+ 19 - 2
src/gui/wizards/UWIZModels.pas

@@ -35,7 +35,7 @@ type
 
     { TModelType }
 
-    TModelType = (omtAccount, omtSendPasc, omtChangeKey, omtTransferAccount, omtChangeAccountPrivateKey, omtAddKey);
+    TModelType = (omtAccount, omtSendPasc, omtChangeKey, omtTransferAccount, omtChangeAccountPrivateKey, omtAddKey, omtEnlistAccountForSale);
 
     { TPayloadEncryptionMode }
 
@@ -49,10 +49,14 @@ type
 
     TChangeKeyMode = (akaTransferAccountOwnership, akaChangeAccountPrivateKey);
 
-     { TSendPASCMode }
+    { TSendPASCMode }
 
     TSendPASCMode = (akaAllBalance, akaSpecifiedAmount);
 
+    { TAccountSaleMode }
+    TAccountSaleMode = (akaPublicSale, akaPrivateSale);
+
+
     { TAccountModel }
 
     TAccountModel = class(TComponent)
@@ -91,6 +95,16 @@ type
       NewWalletKey: TWalletKey;
     end;
 
+    { TWIZEnlistAccountForSaleModel }
+    TEnlistAccountForSaleModel = class(TComponent)
+    public
+      SalePrice: int64;
+      NewOwnerPublicKey: TAccountKey;
+      LockedUntilBlock: cardinal;
+      SellerAccount: TAccount;
+      AccountSaleMode: TAccountSaleMode;
+    end;
+
     { TFeeModel }
 
     TFeeModel = class(TComponent)
@@ -125,6 +139,7 @@ type
     FChangeKey: TChangeKeyModel;
     FTransferAccount: TTransferAccountModel;
     FChangeAccountPrivateKey: TChangeAccountPrivateKeyModel;
+    FEnlistAccountForSale: TEnlistAccountForSaleModel;
     FFee: TFeeModel;
     FSigner: TSignerModel;
     FPayload: TPayloadModel;
@@ -136,6 +151,7 @@ type
     property ChangeKey: TChangeKeyModel read FChangeKey;
     property TransferAccount: TTransferAccountModel read FTransferAccount;
     property ChangeAccountPrivateKey: TChangeAccountPrivateKeyModel read FChangeAccountPrivateKey;
+    property EnlistAccountForSale: TEnlistAccountForSaleModel read FEnlistAccountForSale;
     property Fee: TFeeModel read FFee;
     property Signer: TSignerModel read FSigner;
     property Payload: TPayloadModel read FPayload;
@@ -152,6 +168,7 @@ begin
   FChangeKey := TChangeKeyModel.Create(Self);
   FTransferAccount := TTransferAccountModel.Create(Self);
   FChangeAccountPrivateKey := TChangeAccountPrivateKeyModel.Create(Self);
+  FEnlistAccountForSale := TEnlistAccountForSaleModel.Create(Self);
   FFee := TFeeModel.Create(Self);
   FSigner := TSignerModel.Create(Self);
   FPayload := TPayloadModel.Create(Self);

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

@@ -6,6 +6,7 @@ object WIZChangeKey_Confirmation: TWIZChangeKey_Confirmation
   Caption = 'WIZChangeKey_Confirmation'
   ClientHeight = 320
   ClientWidth = 511
+  LCLVersion = '1.8.2.0'
   Visible = False
   object GroupBox1: TGroupBox
     Left = 10

+ 3 - 29
src/gui/wizards/operations/UWIZChangeKey_Confirmation.pas

@@ -35,7 +35,6 @@ type
   public
     procedure OnPresent; override;
     procedure OnNext; override;
-    function Validate(out message: ansistring): boolean; override;
   end;
 
 
@@ -113,27 +112,11 @@ end;
 
 procedure TWIZChangeKey_Confirmation.OnNext;
 var
-  locked: Boolean;
+  locked: boolean;
 begin
-  locked := (NOT TWallet.Keys.HasPassword) OR (NOT TWallet.Keys.IsValidPassword);
+  locked := (not TWallet.Keys.HasPassword) or (not TWallet.Keys.IsValidPassword);
   if locked then
-  begin
     TUserInterface.UnlockWallet(Self);
-  end;
-end;
-
-function TWIZChangeKey_Confirmation.Validate(out message: ansistring): boolean;
-begin
-  Result := True;
-  if Length(Model.Account.SelectedAccounts) > 1 then
-  begin
-    if not (Model.Fee.SingleOperationFee > 0) then
-    begin
-      message := 'insufficient fee for total operation.';
-      Result := False;
-      Exit;
-    end;
-  end;
 end;
 
 { TAccountChangeKeyDataSource }
@@ -157,20 +140,16 @@ begin
   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'
@@ -180,16 +159,12 @@ begin
             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;
 
@@ -199,9 +174,8 @@ 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;
 
 

+ 59 - 114
src/gui/wizards/operations/UWIZEnlistAccountForSale.pas

@@ -12,41 +12,17 @@ unit UWIZEnlistAccountForSale;
 interface
 
 uses
-  Classes, SysUtils, Forms, Dialogs, UCrypto, UCommon, UWizard, UAccounts, LCLType;
+  Classes, SysUtils, Forms, Dialogs, UCrypto, UCommon, UWizard, UAccounts, UWIZModels, LCLType;
 
 type
 
-  { TWIZEnlistAccountForSaleModel }
-  TWIZAccountSaleMode = (akaPublicSale, akaPrivateSale);
-  TWIZPayloadEncryptionMode = (akaEncryptWithOldEC, akaEncryptWithEC,
-    akaEncryptWithPassword, akaNotEncrypt);
-
-  TWIZEnlistAccountForSaleModel = class(TComponent)
-  public
-    DefaultFee: int64;
-    NewPublicKey, Payload, EncryptionPassword: string;
-    SelectedIndex: integer;
-    SalePrice: int64;
-    NewOwnerPublicKey: TAccountKey;
-    LockedUntilBlock: cardinal;
-    EncodedPayload: TRawBytes;
-    SignerAccount, SellerAccount: TAccount;
-    SelectedAccounts: TArray<TAccount>;
-    PayloadEncryptionMode: TWIZPayloadEncryptionMode;
-    AccountSaleMode: TWIZAccountSaleMode;
-  end;
-
   { TWIZEnlistAccountForSaleWizard }
 
-  TWIZEnlistAccountForSaleWizard = class(TWizard<TWIZEnlistAccountForSaleModel>)
+  TWIZEnlistAccountForSaleWizard = class(TWizard<TWIZOperationsModel>)
   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 UpdateOpListForSale(const TargetAccount: TAccount;
-      var SalePrice: int64; var SellerAccount, SignerAccount: TAccount;
-      var NewOwnerPublicKey: TAccountKey; var LockedUntilBlock: cardinal;
-      var errors: ansistring): boolean;
+    function UpdateOpListForSale(const TargetAccount: TAccount; var SalePrice: int64; var SellerAccount, SignerAccount: TAccount; var NewOwnerPublicKey: TAccountKey; var LockedUntilBlock: cardinal; var errors: ansistring): boolean;
     procedure EnlistAccountForSale();
   public
     constructor Create(AOwner: TComponent); override;
@@ -66,13 +42,15 @@ uses
   UWallet,
   UECIES,
   UAES,
-  UWIZEnlistAccountForSale_Start,
+  UWIZEnlistAccountForSale_ConfirmAccount,
+  UWIZEnlistAccountForSale_SelectOption,
+  UWIZEnlistAccountForSale_EnterSeller,
+  UWIZEnlistAccountForSale_EnterSaleAmount,
   UWIZEnlistAccountForSale_Confirmation;
 
 { TWIZEnlistAccountForSaleWizard }
 
-function TWIZEnlistAccountForSaleWizard.UpdatePayload(const SenderAccount: TAccount;
-  var errors: string): boolean;
+function TWIZEnlistAccountForSaleWizard.UpdatePayload(const SenderAccount: TAccount; var errors: string): boolean;
 var
   valid: boolean;
   payload_encrypted, payload_u: string;
@@ -80,9 +58,9 @@ var
 begin
   valid := False;
   payload_encrypted := '';
-  Model.EncodedPayload := '';
+  Model.Payload.EncodedBytes := '';
   errors := 'Unknown error';
-  payload_u := Model.Payload;
+  payload_u := Model.Payload.Content;
 
   try
     if (payload_u = '') then
@@ -90,9 +68,9 @@ begin
       valid := True;
       Exit;
     end;
-    case Model.PayloadEncryptionMode of
+    case Model.Payload.Mode of
 
-      akaEncryptWithOldEC:
+      akaEncryptWithSender:
       begin
         // Use sender
         errors := 'Error encrypting';
@@ -101,11 +79,11 @@ begin
         valid := payload_encrypted <> '';
       end;
 
-      akaEncryptWithEC:
+      akaEncryptWithReceiver:
       begin
         errors := 'Public key: ' + 'Error encrypting';
 
-        account := Model.SignerAccount;
+        account := Model.Signer.SignerAccount;
         payload_encrypted := ECIESEncrypt(account.accountInfo.accountKey, payload_u);
         valid := payload_encrypted <> '';
       end;
@@ -113,7 +91,7 @@ begin
       akaEncryptWithPassword:
       begin
         payload_encrypted := TAESComp.EVP_Encrypt_AES256(
-          payload_u, Model.EncryptionPassword);
+          payload_u, Model.Payload.Password);
         valid := payload_encrypted <> '';
       end;
 
@@ -124,30 +102,24 @@ begin
       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.EncodedPayload := payload_encrypted;
+    Model.Payload.EncodedBytes := payload_encrypted;
     Result := valid;
   end;
 
 end;
 
-function TWIZEnlistAccountForSaleWizard.UpdateOperationOptions(
-  var errors: string): boolean;
+function TWIZEnlistAccountForSaleWizard.UpdateOperationOptions(var errors: string): boolean;
 var
   iAcc, iWallet: integer;
   sender_account, signer_account, seller_account: TAccount;
@@ -165,17 +137,15 @@ begin
     Exit;
   end;
 
-  if Length(Model.SelectedAccounts) = 0 then
+  if Length(Model.Account.SelectedAccounts) = 0 then
   begin
     errors := 'No sender account';
     Exit;
   end
   else
-  begin
-
-    for iAcc := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
     begin
-      sender_account := Model.SelectedAccounts[iAcc];
+      sender_account := Model.Account.SelectedAccounts[iAcc];
       iWallet := TWallet.Keys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
       if (iWallet < 0) then
       begin
@@ -188,30 +158,22 @@ begin
       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
+          errors := 'Wallet is password protected. Need password'// TODO: handle unlocking of encrypted wallet here
+
         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 := UpdateOpListForSale(Model.SelectedAccounts[0], salePrice,
+  Result := UpdateOpListForSale(Model.Account.SelectedAccounts[0], salePrice,
     seller_account, signer_account, publicKey, auxC, errors);
   UpdatePayload(sender_account, e);
 end;
 
-function TWIZEnlistAccountForSaleWizard.UpdateOpListForSale(
-  const TargetAccount: TAccount; var SalePrice: int64;
-  var SellerAccount, SignerAccount: TAccount; var NewOwnerPublicKey: TAccountKey;
-  var LockedUntilBlock: cardinal; var errors: ansistring): boolean;
+function TWIZEnlistAccountForSaleWizard.UpdateOpListForSale(const TargetAccount: TAccount; var SalePrice: int64; var SellerAccount, SignerAccount: TAccount; var NewOwnerPublicKey: TAccountKey; var LockedUntilBlock: cardinal; var errors: ansistring): boolean;
 begin
   Result := False;
   SalePrice := 0;
@@ -226,21 +188,21 @@ begin
         TargetAccount.account) + ' is already enlisted for sale';
       Exit;
     end;
-    salePrice := Model.SalePrice;
+    salePrice := Model.EnlistAccountForSale.SalePrice;
 
-    SignerAccount := Model.SignerAccount;
+    SignerAccount := Model.Signer.SignerAccount;
 
-    if (Model.SellerAccount.account = TargetAccount.account) then
+    if (Model.EnlistAccountForSale.SellerAccount.account = TargetAccount.account) then
     begin
       errors := 'Seller account cannot be same account';
       exit;
     end;
 
-    SellerAccount := Model.SellerAccount;
-    if Model.AccountSaleMode = akaPrivateSale then
+    SellerAccount := Model.EnlistAccountForSale.SellerAccount;
+    if Model.EnlistAccountForSale.AccountSaleMode = akaPrivateSale then
     begin
 
-      NewOwnerPublicKey := Model.NewOwnerPublicKey;
+      NewOwnerPublicKey := Model.EnlistAccountForSale.NewOwnerPublicKey;
 
       if TAccountComp.EqualAccountKeys(NewOwnerPublicKey,
         TargetAccount.accountInfo.accountKey) then
@@ -248,7 +210,7 @@ begin
         errors := 'New public key for private sale is the same public key';
         Exit;
       end;
-      LockedUntilBlock := Model.LockedUntilBlock;
+      LockedUntilBlock := Model.EnlistAccountForSale.LockedUntilBlock;
       if LockedUntilBlock = 0 then
       begin
         errors := 'Insert locking block';
@@ -294,21 +256,17 @@ begin
     _signer_n_ops := 0;
     operationstxt := '';
     operation_to_string := '';
-    for iAcc := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+    for iAcc := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
     begin
       loop_start:
         op := nil;
-      account := Model.SelectedAccounts[iAcc];
+      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;
@@ -320,32 +278,24 @@ begin
 
       if not UpdateOpListForSale(account, _salePrice, destAccount,
         signerAccount, _newOwnerPublicKey, _lockedUntil, errors) then
-      begin
         raise Exception.Create(errors);
-      end;
       // Special fee account:
       if signerAccount.balance > Model.Fee.DefaultFee then
         _fee := Model.Fee.DefaultFee
       else
         _fee := signerAccount.balance;
-      if Model.AccountSaleMode = akaPublicSale then
-      begin
+      if Model.EnlistAccountForSale.AccountSaleMode = akaPublicSale then
         op := TOpListAccountForSale.CreateListAccountForSale(
           signerAccount.account, signerAccount.n_operation + 1 + iAcc,
           account.account, _salePrice, _fee, destAccount.account,
-          CT_TECDSA_Public_Nul, 0, wk.PrivateKey, Model.EncodedPayload);
-      end
-      else if Model.AccountSaleMode = akaPrivateSale then
-      begin
+          CT_TECDSA_Public_Nul, 0, wk.PrivateKey, Model.Payload.EncodedBytes)
+      else if Model.EnlistAccountForSale.AccountSaleMode = akaPrivateSale then
         op := TOpListAccountForSale.CreateListAccountForSale(
           signerAccount.account, signerAccount.n_operation + 1 + iAcc,
           account.account, _salePrice, _fee, destAccount.account,
-          _newOwnerPublicKey, _lockedUntil, wk.PrivateKey, Model.EncodedPayload);
-      end
+          _newOwnerPublicKey, _lockedUntil, wk.PrivateKey, Model.Payload.EncodedBytes)
       else
-      begin
         raise Exception.Create('Invalid Sale type');
-      end;
 
       if Assigned(op) and (dooperation) then
       begin
@@ -360,41 +310,32 @@ begin
     if (ops.OperationsCount = 0) then
       raise Exception.Create('No valid operation to execute');
 
-    if (Length(Model.SelectedAccounts) > 1) then
+    if (Length(Model.Account.SelectedAccounts) > 1) then
     begin
       auxs := '';
       if Application.MessageBox(
-        PChar('Execute ' + IntToStr(Length(Model.SelectedAccounts)) +
+        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;
+    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
+      Exit;
     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
+        ShowMessage(operationstxt)
       else
       begin
         Application.MessageBox(
@@ -413,9 +354,7 @@ begin
       ShowMessage(operationstxt);
     end
     else
-    begin
       raise Exception.Create(errors);
-    end;
 
 
   finally
@@ -426,8 +365,15 @@ end;
 
 constructor TWIZEnlistAccountForSaleWizard.Create(AOwner: TComponent);
 begin
-  inherited Create(AOwner, [TWIZEnlistAccountForSale_Start,
-    TWIZEnlistAccountForSale_Confirmation]);
+  inherited Create(AOwner,
+    [
+    TWIZEnlistAccountForSale_ConfirmAccount,
+    TWIZEnlistAccountForSale_SelectOption,
+    TWIZEnlistAccountForSale_EnterSeller,
+    TWIZEnlistAccountForSale_EnterSaleAmount,
+    TWIZEnlistAccountForSale_Confirmation
+    ]
+    );
   TitleText := 'Enlist Account';
   FinishText := 'Enlist Account';
 end;
@@ -442,8 +388,7 @@ begin
   Result := inherited DetermineHasPrevious;
 end;
 
-function TWIZEnlistAccountForSaleWizard.FinishRequested(
-  out message: ansistring): boolean;
+function TWIZEnlistAccountForSaleWizard.FinishRequested(out message: ansistring): boolean;
 begin
   // Execute the Enlist Account For Sale Action here
   try
@@ -458,8 +403,8 @@ begin
   end;
 end;
 
-function TWIZEnlistAccountForSaleWizard.CancelRequested(
-  out message: ansistring): boolean;
+function TWIZEnlistAccountForSaleWizard.CancelRequested(out message: ansistring): boolean;
+
 begin
   Result := True;
 end;

+ 4 - 4
src/gui/wizards/operations/UWIZEnlistAccountForSale_List.lfm → src/gui/wizards/operations/UWIZEnlistAccountForSale_ConfirmAccount.lfm

@@ -1,14 +1,14 @@
-object WIZEnlistAccountForSale_List: TWIZEnlistAccountForSale_List
+object WIZEnlistAccountForSale_ConfirmAccount: TWIZEnlistAccountForSale_ConfirmAccount
   Left = 0
   Height = 253
   Top = 0
   Width = 429
-  Caption = 'WIZEnlistAccountForSale_List'
+  Caption = 'WIZEnlistAccountForSale_ConfirmAccount'
   ClientHeight = 253
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
+  LCLVersion = '1.8.2.0'
   Visible = False
-  object grpTransferAccount: TGroupBox
+  object grpEnlistAccount: TGroupBox
     Left = 6
     Height = 248
     Top = 0

+ 128 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_ConfirmAccount.pas

@@ -0,0 +1,128 @@
+unit UWIZEnlistAccountForSale_ConfirmAccount;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UVisualGrid, UCommon.Data, UCellRenderers, UWizard, UWIZModels;
+
+type
+
+  { TWIZEnlistAccountForSale_ConfirmAccount }
+
+  TWIZEnlistAccountForSale_ConfirmAccount = class(TWizardForm<TWIZOperationsModel>)
+    grpEnlistAccountForSale: TGroupBox;
+    grpEnlistAccount: TGroupBox;
+    paGrid: TPanel;
+  private
+    FEnlistAccountsGrid: TVisualGrid;
+  public
+    procedure OnPresent; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts, USettings, UCoreUtils, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+
+type
+
+  { TAccountSenderDataSource }
+
+  TAccountSenderDataSource = class(TAccountsDataSourceBase)
+  private
+    FModel: TWIZOperationsModel;
+  public
+    property Model: TWIZOperationsModel read FModel write FModel;
+    procedure FetchAll(const AContainer: TList<TAccount>); override;
+  end;
+
+{ TWIZEnlistAccountForSale_ConfirmAccount }
+
+procedure TWIZEnlistAccountForSale_ConfirmAccount.OnPresent;
+var
+  Data: TAccountSenderDataSource;
+begin
+  FEnlistAccountsGrid := TVisualGrid.Create(Self);
+  FEnlistAccountsGrid.CanSearch := False;
+  FEnlistAccountsGrid.SortMode := smMultiColumn;
+  FEnlistAccountsGrid.FetchDataInThread := False;
+  FEnlistAccountsGrid.AutoPageSize := True;
+  FEnlistAccountsGrid.SelectionType := stNone;
+  FEnlistAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone,
+    vgoAutoHidePaging];
+  with FEnlistAccountsGrid.AddColumn('Account') do
+  begin
+    StretchedToFill := True;
+    Binding := 'AccountNumber';
+    SortBinding := 'AccountNumber';
+    DisplayBinding := 'Account';
+    Width := 100;
+    HeaderFontStyles := [fsBold];
+    DataFontStyles := [fsBold];
+    Filters := SORTABLE_NUMERIC_FILTER;
+  end;
+  with FEnlistAccountsGrid.AddColumn('Balance') do
+  begin
+    Binding := 'BalanceDecimal';
+    SortBinding := 'Balance';
+    DisplayBinding := 'Balance';
+    Width := 100;
+    HeaderAlignment := taRightJustify;
+    DataAlignment := taRightJustify;
+    Renderer := TCellRenderers.PASC;
+    Filters := SORTABLE_NUMERIC_FILTER;
+  end;
+  Data := TAccountSenderDataSource.Create(FEnlistAccountsGrid);
+  Data.Model := Model;
+  FEnlistAccountsGrid.DataSource := Data;
+  paGrid.AddControlDockCenter(FEnlistAccountsGrid);
+end;
+
+function TWIZEnlistAccountForSale_ConfirmAccount.Validate(out message: ansistring): boolean;
+var
+  i: integer;
+begin
+  Result := True;
+  for i := Low(model.Account.SelectedAccounts) to High(model.Account.SelectedAccounts) do
+    if TAccountComp.IsAccountForSale(model.Account.SelectedAccounts[i].accountInfo) then
+    begin
+      Result := False;
+      message := 'Account ' + TAccountComp.AccountNumberToAccountTxtNumber(
+        model.Account.SelectedAccounts[i].account) + ' is already enlisted for sale';
+      Exit;
+    end;
+
+  // 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;
+
+procedure TAccountSenderDataSource.FetchAll(const AContainer: TList<TAccount>);
+var
+  i: integer;
+begin
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+    AContainer.Add(Model.Account.SelectedAccounts[i]);
+end;
+
+
+end.

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

@@ -6,6 +6,7 @@ object WIZEnlistAccountForSale_Confirmation: TWIZEnlistAccountForSale_Confirmati
   Caption = 'WIZEnlistAccountForSale_Confirmation'
   ClientHeight = 253
   ClientWidth = 429
+  LCLVersion = '1.8.2.0'
   Visible = False
   object GroupBox1: TGroupBox
     Left = 10

+ 38 - 33
src/gui/wizards/operations/UWIZEnlistAccountForSale_Confirmation.pas

@@ -13,13 +13,13 @@ interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, UVisualGrid, UCellRenderers, UCommon.Data, UWizard, UWIZEnlistAccountForSale;
+  ExtCtrls, UVisualGrid, UCellRenderers, UCommon.Data, UWizard, UWIZModels;
 
 type
 
   { TWIZEnlistAccountForSale_Confirmation }
 
-  TWIZEnlistAccountForSale_Confirmation = class(TWizardForm<TWIZEnlistAccountForSaleModel>)
+  TWIZEnlistAccountForSale_Confirmation = class(TWizardForm<TWIZOperationsModel>)
     GroupBox1: TGroupBox;
     Label1: TLabel;
     Label2: TLabel;
@@ -27,9 +27,10 @@ type
     lblSellerAcc: TLabel;
     paGrid: TPanel;
   private
-    FSendersGrid : TVisualGrid;
+    FEnlistAccountsGrid : TVisualGrid;
   public
     procedure OnPresent; override;
+    procedure OnNext; override;
   end;
 
 
@@ -37,7 +38,7 @@ implementation
 
 {$R *.lfm}
 
-uses UAccounts, UDataSources, UCommon, UCommon.UI, Generics.Collections;
+uses UAccounts, UWallet, UUserInterface, UDataSources, UCommon, UCommon.UI, Generics.Collections;
 
 type
 
@@ -45,11 +46,11 @@ type
 
   TAccountSenderDataSource = class(TAccountsDataSourceBase)
     private
-      FModel : TWIZEnlistAccountForSaleModel;
+      FModel : TWIZOperationsModel;
     protected
       function GetColumns : TDataColumns; override;
     public
-      property Model : TWIZEnlistAccountForSaleModel read FModel write FModel;
+      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;
@@ -60,43 +61,50 @@ procedure TWIZEnlistAccountForSale_Confirmation.OnPresent;
 var
   data : TAccountSenderDataSource;
 begin
-  FSendersGrid := TVisualGrid.Create(Self);
-  FSendersGrid.CanSearch:= False;
-  FSendersGrid.SortMode := smMultiColumn;
-  FSendersGrid.FetchDataInThread := False;
-  FSendersGrid.AutoPageSize := True;
-  FSendersGrid.SelectionType := stNone;
-  FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
-  with FSendersGrid.AddColumn('Account') do begin
+  FEnlistAccountsGrid := TVisualGrid.Create(Self);
+  FEnlistAccountsGrid.CanSearch:= False;
+  FEnlistAccountsGrid.SortMode := smMultiColumn;
+  FEnlistAccountsGrid.FetchDataInThread := False;
+  FEnlistAccountsGrid.AutoPageSize := True;
+  FEnlistAccountsGrid.SelectionType := stNone;
+  FEnlistAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging];
+  with FEnlistAccountsGrid.AddColumn('Account') do begin
     Binding := 'Account';
     Filters := SORTABLE_NUMERIC_FILTER;
     Width := 100;
     HeaderFontStyles := [fsBold];
     DataFontStyles := [fsBold];
   end;
-   with FSendersGrid.AddColumn('Sale Price') do begin
+   with FEnlistAccountsGrid.AddColumn('Sale Price') do begin
     Binding := 'SalePrice';
     Filters := SORTABLE_NUMERIC_FILTER;
     Width := 100;
     Renderer := TCellRenderers.PASC;
   end;
-  // with FSendersGrid.AddColumn('New Public Key') do begin
-  //  Binding := 'NewPublicKey';
-  //  Filters := SORTABLE_TEXT_FILTER;
-  //  Width := 100;
-  //end;
-  with FSendersGrid.AddColumn('Fee') do begin
+
+  with FEnlistAccountsGrid.AddColumn('Fee') do begin
     Filters := SORTABLE_TEXT_FILTER;
     Width := 100;
   end;
 
-   data := TAccountSenderDataSource.Create(FSendersGrid);
+   data := TAccountSenderDataSource.Create(FEnlistAccountsGrid);
    data.Model := Model;
-   FSendersGrid.DataSource := data;
-   paGrid.AddControlDockCenter(FSendersGrid);
-   lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.SignerAccount.account);
-   lblSellerAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.SellerAccount.account);
+   FEnlistAccountsGrid.DataSource := data;
+   paGrid.AddControlDockCenter(FEnlistAccountsGrid);
+   lblSgnAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.Signer.SignerAccount.account);
+   lblSellerAcc.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Model.EnlistAccountForSale.SellerAccount.account);
+
+end;
 
+procedure TWIZEnlistAccountForSale_Confirmation.OnNext;
+var
+  locked: Boolean;
+begin
+  locked := (NOT TWallet.Keys.HasPassword) OR (NOT TWallet.Keys.IsValidPassword);
+  if locked then
+  begin
+    TUserInterface.UnlockWallet(Self);
+  end;
 end;
 
 { TAccountSenderDataSource }
@@ -106,7 +114,6 @@ begin
   Result := TDataColumns.Create(
     TDataColumn.From('Account'),
     TDataColumn.From('SalePrice'),
-    //TDataColumn.From('NewPublicKey'),
     TDataColumn.From('Fee')
   );
 end;
@@ -118,11 +125,9 @@ begin
    if ABindingName = 'Account' then
      Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
    else if ABindingName = 'SalePrice' then
-     Result := TAccountComp.FormatMoney(Model.SalePrice)
-   //else if ABindingName = 'NewPublicKey' then
-   //  Result := Model.NewPublicKey
+     Result := TAccountComp.FormatMoney(Model.EnlistAccountForSale.SalePrice)
      else if ABindingName = 'Fee' then
-     Result := TAccountComp.FormatMoney(Model.Fee.DefaultFee)
+     Result := TAccountComp.FormatMoney(Model.Fee.SingleOperationFee)
    else raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
 end;
 
@@ -131,9 +136,9 @@ procedure TAccountSenderDataSource.FetchAll(const AContainer : TList<TAccount>);
 var
   i: Integer;
 begin
-  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
   begin
-    AContainer.Add( Model.SelectedAccounts[i] );
+    AContainer.Add( Model.Account.SelectedAccounts[i] );
   end;
 end;
 

+ 36 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterLockingBlock.lfm

@@ -0,0 +1,36 @@
+object WIZEnlistAccountForSale_EnterLockingBlock: TWIZEnlistAccountForSale_EnterLockingBlock
+  Left = 0
+  Height = 253
+  Top = 40
+  Width = 429
+  ActiveControl = edtBlockLock
+  Caption = 'WIZEnlistAccountForSale_EnterLockingBlock'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object gbLockBlock: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 400
+    Caption = 'Enter Locking Block'
+    ClientHeight = 212
+    ClientWidth = 396
+    TabOrder = 0
+    object lblBlockLock: TLabel
+      Left = 8
+      Height = 15
+      Top = 8
+      Width = 378
+      Caption = 'Please enter the block at which this sale will be allowed to succeed from'
+      ParentColor = False
+    end
+    object edtBlockLock: TEdit
+      Left = 8
+      Height = 23
+      Top = 48
+      Width = 152
+      TabOrder = 0
+    end
+  end
+end

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

@@ -0,0 +1,63 @@
+unit UWIZEnlistAccountForSale_EnterLockingBlock;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UWizard, UWIZModels, UWIZEnlistAccountForSale_EnterSeller;
+
+type
+
+  { TWIZEnlistAccountForSale_EnterLockingBlock }
+
+  TWIZEnlistAccountForSale_EnterLockingBlock = class(TWizardForm<TWIZOperationsModel>)
+    edtBlockLock: TEdit;
+    gbLockBlock: TGroupBox;
+    lblBlockLock: TLabel;
+  public
+    procedure OnPresent; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts;
+
+{ TWIZEnlistAccountForSale_EnterLockingBlock }
+
+procedure TWIZEnlistAccountForSale_EnterLockingBlock.OnPresent;
+begin
+  edtBlockLock.SetFocus;
+end;
+
+function TWIZEnlistAccountForSale_EnterLockingBlock.Validate(out message: ansistring): boolean;
+var
+  LockedUntilBlock: cardinal;
+begin
+  Result := True;
+
+  LockedUntilBlock := StrToIntDef(edtBlockLock.Text, 0);
+  if LockedUntilBlock = 0 then
+  begin
+    message := 'Insert locking block';
+    Result := False;
+    exit;
+  end;
+  Model.EnlistAccountForSale.LockedUntilBlock := LockedUntilBlock;
+
+end;
+
+end.

+ 36 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterPublicKey.lfm

@@ -0,0 +1,36 @@
+object WIZEnlistAccountForSale_EnterPublicKey: TWIZEnlistAccountForSale_EnterPublicKey
+  Left = 0
+  Height = 253
+  Top = 40
+  Width = 429
+  ActiveControl = mmoPublicKey
+  Caption = 'WIZEnlistAccountForSale_EnterPublicKey'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object gbTransaction: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 400
+    Caption = 'Enter Public Key'
+    ClientHeight = 212
+    ClientWidth = 396
+    TabOrder = 0
+    object lblPublicKey: TLabel
+      Left = 8
+      Height = 15
+      Top = 8
+      Width = 377
+      Caption = 'Please Enter the Public Key of the account you wish to make the sale to.'
+      ParentColor = False
+    end
+    object mmoPublicKey: TMemo
+      Left = 8
+      Height = 144
+      Top = 40
+      Width = 378
+      TabOrder = 0
+    end
+  end
+end

+ 79 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterPublicKey.pas

@@ -0,0 +1,79 @@
+unit UWIZEnlistAccountForSale_EnterPublicKey;
+
+{$mode delphi}
+{$modeswitch nestedprocvars}
+
+{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Buttons, UWizard, UWIZModels, UWIZEnlistAccountForSale_EnterLockingBlock;
+
+type
+
+  { TWIZEnlistAccountForSale_EnterPublicKey }
+
+  TWIZEnlistAccountForSale_EnterPublicKey = class(TWizardForm<TWIZOperationsModel>)
+    gbTransaction: TGroupBox;
+    lblBlockLock: TLabel;
+    lblPublicKey: TLabel;
+    mmoPublicKey: TMemo;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts;
+
+{ TWIZEnlistAccountForSale_EnterPublicKey }
+
+procedure TWIZEnlistAccountForSale_EnterPublicKey.OnPresent;
+begin
+  mmoPublicKey.SetFocus;
+end;
+
+procedure TWIZEnlistAccountForSale_EnterPublicKey.OnNext;
+begin
+   UpdatePath(ptInject, [TWIZEnlistAccountForSale_EnterLockingBlock]);
+end;
+
+function TWIZEnlistAccountForSale_EnterPublicKey.Validate(out message: ansistring): boolean;
+var
+  i: integer;
+begin
+  Result := True;
+
+  if not TAccountComp.AccountKeyFromImport(mmoPublicKey.Text,
+    Model.EnlistAccountForSale.NewOwnerPublicKey, message) then
+  begin
+    message := 'Public key: ' + message;
+    Result := False;
+    exit;
+
+  end;
+
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+    if TAccountComp.EqualAccountKeys(Model.EnlistAccountForSale.NewOwnerPublicKey,
+      Model.Account.SelectedAccounts[i].accountInfo.accountKey) then
+    begin
+      message := 'New public key for private sale is the same public key';
+      Result := False;
+      Exit;
+    end;
+
+end;
+
+end.

+ 52 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSaleAmount.lfm

@@ -0,0 +1,52 @@
+object WIZEnlistAccountForSale_EnterSaleAmount: TWIZEnlistAccountForSale_EnterSaleAmount
+  Left = 0
+  Height = 253
+  Top = 0
+  Width = 429
+  ActiveControl = edtAmt
+  Caption = 'WIZEnlistAccountForSale_EnterSaleAmount'
+  ClientHeight = 253
+  ClientWidth = 429
+  Visible = False
+  object gbSaleAmount: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 400
+    Caption = 'Sale Amount'
+    ClientHeight = 212
+    ClientWidth = 396
+    TabOrder = 0
+    object edtAmt: TEdit
+      Left = 8
+      Height = 23
+      Top = 40
+      Width = 160
+      TabOrder = 0
+    end
+    object lblSaleAmountNotice: TLabel
+      Left = 8
+      Height = 15
+      Top = 7
+      Width = 293
+      Caption = 'Please enter the amount you wish to sell EACH PASA at.'
+      ParentColor = 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 = 110
+      Width = 303
+      Caption = 'I want to attach a message payload to this transaction'
+      TabOrder = 2
+    end
+  end
+end

+ 118 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSaleAmount.pas

@@ -0,0 +1,118 @@
+unit UWIZEnlistAccountForSale_EnterSaleAmount;
+
+{$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, UWIZOperationFee_Custom, UWIZOperationPayload_Encryption, UWIZOperationSigner_Select,
+  UWIZEnlistAccountForSale_Confirmation, UWIZModels;
+
+type
+
+  { TWIZEnlistAccountForSale_EnterSaleAmount }
+
+  TWIZEnlistAccountForSale_EnterSaleAmount = class(TWizardForm<TWIZOperationsModel>)
+    chkChooseFee: TCheckBox;
+    chkAttachPayload: TCheckBox;
+    edtAmt: TEdit;
+    gbSaleAmount: TGroupBox;
+    lblSaleAmountNotice: TLabel;
+    procedure UpdateUI();
+
+
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UUserInterface, USettings;
+
+{ TWIZSendPASC_EnterQuantity }
+
+procedure TWIZEnlistAccountForSale_EnterSaleAmount.UpdateUI();
+begin
+  edtAmt.Text := TAccountComp.FormatMoney(0);
+end;
+
+procedure TWIZEnlistAccountForSale_EnterSaleAmount.OnPresent;
+begin
+  UpdateUI();
+  if Length(Model.Account.SelectedAccounts) > 1 then
+  begin
+    chkChooseFee.Checked := True;
+    chkChooseFee.Enabled := False;
+  end;
+  if edtAmt.Enabled then
+    edtAmt.SetFocus;
+end;
+
+procedure TWIZEnlistAccountForSale_EnterSaleAmount.OnNext;
+var
+  amount: int64;
+begin
+  Model.Payload.HasPayload := chkAttachPayload.Checked;
+  TAccountComp.TxtToMoney(edtAmt.Text, Model.EnlistAccountForSale.SalePrice);
+
+  if chkChooseFee.Checked then
+    UpdatePath(ptReplaceAllNext, [TWIZOperationFee_Custom, TWIZEnlistAccountForSale_Confirmation])
+  else
+  begin
+    Model.Fee.SingleOperationFee := TSettings.DefaultFee;
+    if Model.Payload.HasPayload then
+      UpdatePath(ptReplaceAllNext, [TWIZOperationPayload_Encryption, TWIZEnlistAccountForSale_Confirmation])
+    else if Length(Model.Account.SelectedAccounts) > 1 then
+      UpdatePath(ptReplaceAllNext, [TWIZOperationSigner_Select, TWIZEnlistAccountForSale_Confirmation])
+    else
+    begin
+      Model.Signer.SignerAccount := Model.Account.SelectedAccounts[0];
+      Model.Signer.OperationSigningMode := akaPrimary;
+    end;
+  end;
+
+end;
+
+function TWIZEnlistAccountForSale_EnterSaleAmount.Validate(out message: ansistring): boolean;
+var
+  amount: int64;
+begin
+  Result := True;
+
+  if not TAccountComp.TxtToMoney(edtAmt.Text, amount) then
+  begin
+    message := 'Invalid amount (' + edtAmt.Text + ')';
+    Result := False;
+    Exit;
+  end;
+
+  if amount < 1 then
+  begin
+    message := 'Invalid amount (' + edtAmt.Text + '), you must sell for an amount greater than zero';
+    Result := False;
+    Exit;
+  end;
+
+end;
+
+end.

+ 53 - 87
src/gui/wizards/operations/UWIZEnlistAccountForSale_Transaction.lfm → src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSeller.lfm

@@ -1,65 +1,34 @@
-object WIZEnlistAccountForSale_Transaction: TWIZEnlistAccountForSale_Transaction
+object WIZEnlistAccountForSale_EnterSeller: TWIZEnlistAccountForSale_EnterSeller
   Left = 0
   Height = 253
-  Top = 40
+  Top = 0
   Width = 429
-  ActiveControl = cbSignerAccount
-  Caption = 'WIZEnlistAccountForSale_Transaction'
+  ActiveControl = edtSellerAcc
+  Caption = 'WIZEnlistAccountForSale_EnterSeller'
   ClientHeight = 253
   ClientWidth = 429
-  LCLVersion = '1.8.2.0'
   Visible = False
-  object gbTransaction: TGroupBox
-    Left = 24
-    Height = 192
-    Top = 40
-    Width = 384
-    Caption = 'Sale Transaction'
-    ClientHeight = 172
-    ClientWidth = 380
+  object gbSeller: TGroupBox
+    Left = 16
+    Height = 232
+    Top = 8
+    Width = 398
+    Caption = 'Seller Account'
+    ClientHeight = 212
+    ClientWidth = 394
     TabOrder = 0
-    object cbSignerAccount: TComboBox
+    object edtSellerAcc: TEdit
       Left = 8
       Height = 23
-      Top = 8
-      Width = 168
-      ItemHeight = 15
-      Items.Strings = (
-        ''
-      )
-      OnChange = cbSignerAccountChange
-      TabOrder = 0
-      Text = 'Select Signer Account'
-    end
-    object lblBalance: TLabel
-      Left = 200
-      Height = 15
-      Top = 12
-      Width = 151
-      Caption = 'Please Select Signer Account'
-      Font.Color = clRed
-      ParentColor = False
-      ParentFont = False
-    end
-    object lblSalePrice: TLabel
-      Left = 8
-      Height = 15
-      Top = 48
-      Width = 50
-      Caption = 'Sale Price'
-      ParentColor = False
-    end
-    object edtSalePrice: TEdit
-      Left = 8
-      Height = 23
-      Top = 74
+      Top = 40
       Width = 136
-      TabOrder = 1
+      OnChange = edtSellerAccChange
+      TabOrder = 0
     end
     object btnSearch: TSpeedButton
-      Left = 345
+      Left = 152
       Height = 22
-      Top = 75
+      Top = 41
       Width = 23
       Glyph.Data = {
         36040000424D3604000000000000360000002800000010000000100000000100
@@ -99,53 +68,50 @@ object WIZEnlistAccountForSale_Transaction: TWIZEnlistAccountForSale_Transaction
       }
       OnClick = btnSearchClick
     end
-    object lblOpFee: TLabel
+    object lblDestNotice: TLabel
       Left = 8
       Height = 15
-      Top = 112
-      Width = 74
-      Caption = 'Operation Fee'
+      Top = 8
+      Width = 380
+      Caption = 'Please enter the seller account that will receive the payments for the sale'
       ParentColor = False
+      ParentFont = False
     end
-    object edtOpFee: TEdit
+    object lblSellerAccNumber: TLabel
       Left = 8
-      Height = 23
-      Top = 136
-      Width = 360
-      TabOrder = 2
+      Height = 15
+      Top = 80
+      Width = 126
+      Caption = 'Seller Account Number:'
+      ParentColor = False
+      ParentFont = False
     end
-    object edtSellerAccount: TEdit
-      Left = 200
-      Height = 23
-      Top = 74
-      Width = 136
-      TabOrder = 3
+    object lblSellerAccNumberName: TLabel
+      Left = 8
+      Height = 15
+      Top = 108
+      Width = 161
+      Caption = 'Seller Account Number Name:'
+      ParentColor = False
+      ParentFont = False
     end
-    object lblSellerAccount: TLabel
-      Left = 200
+    object lblSellerAccNumberValue: TLabel
+      Left = 224
       Height = 15
-      Top = 48
-      Width = 76
-      Caption = 'Seller Account'
+      Top = 80
+      Width = 92
+      Caption = 'Account Number'
       ParentColor = False
+      ParentFont = False
+    end
+    object lblSellerAccNumberNameValue: TLabel
+      Left = 224
+      Height = 15
+      Top = 108
+      Width = 121
+      Caption = 'AccountNumberName'
+      ParentColor = False
+      ParentFont = False
     end
-  end
-  object lblTotalBalances: TLabel
-    Left = 24
-    Height = 15
-    Top = 16
-    Width = 176
-    Caption = 'Selected Accounts Total Balance: '
-    ParentColor = False
-  end
-  object lblTotalBalanceValue: TLabel
-    Left = 208
-    Height = 15
-    Top = 16
-    Width = 70
-    Caption = 'Total Balance'
-    Font.Color = clGreen
-    ParentColor = False
-    ParentFont = False
   end
 end

+ 159 - 0
src/gui/wizards/operations/UWIZEnlistAccountForSale_EnterSeller.pas

@@ -0,0 +1,159 @@
+unit UWIZEnlistAccountForSale_EnterSeller;
+
+{$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, UWIZModels;
+
+type
+
+  { TWIZEnlistAccountForSale_EnterSeller }
+
+  TWIZEnlistAccountForSale_EnterSeller = class(TWizardForm<TWIZOperationsModel>)
+    edtSellerAcc: TEdit;
+    gbSeller: TGroupBox;
+    lblSellerAccNumber: TLabel;
+    lblSellerAccNumberValue: TLabel;
+    lblSellerAccNumberName: TLabel;
+    lblSellerAccNumberNameValue: TLabel;
+    lblDestNotice: TLabel;
+    btnSearch: TSpeedButton;
+    procedure btnSearchClick(Sender: TObject);
+    procedure edtSellerAccChange(Sender: TObject);
+    procedure UpdateUI();
+
+
+
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message: ansistring): boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses
+  UAccounts, UUserInterface, USettings;
+
+{ TWIZEnlistAccountForSale_EnterSeller }
+
+procedure TWIZEnlistAccountForSale_EnterSeller.edtSellerAccChange(Sender: TObject);
+begin
+  UpdateUI();
+end;
+
+procedure TWIZEnlistAccountForSale_EnterSeller.UpdateUI();
+var
+  tempAcc: TAccount;
+  c: cardinal;
+begin
+  if TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAcc.Text, c) then
+  begin
+    if (c < 0) or (c >= TNode.Node.Bank.AccountsCount) then
+    begin
+      lblSellerAccNumberValue.Caption := 'unknown';
+      lblSellerAccNumberNameValue.Caption := 'unknown';
+      Exit;
+    end;
+    tempAcc := TNode.Node.Operations.SafeBoxTransaction.account(c);
+    lblSellerAccNumberValue.Caption := edtSellerAcc.Text;
+    lblSellerAccNumberNameValue.Caption := tempAcc.Name;
+  end
+  else
+  begin
+    lblSellerAccNumberValue.Caption := 'unknown';
+    lblSellerAccNumberNameValue.Caption := 'unknown';
+  end;
+
+end;
+
+procedure TWIZEnlistAccountForSale_EnterSeller.OnPresent;
+begin
+  UpdateUI();
+  edtSellerAcc.SetFocus;
+end;
+
+procedure TWIZEnlistAccountForSale_EnterSeller.btnSearchClick(Sender: TObject);
+var
+  F: TFRMAccountSelect;
+  c: cardinal;
+begin
+  F := TFRMAccountSelect.Create(Self);
+  F.Position := poMainFormCenter;
+  try
+    F.Node := TNode.Node;
+    F.WalletKeys := TWallet.Keys;
+    F.Filters := edtSellerAcc.Tag;
+    if TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAcc.Text, c) then
+      F.DefaultAccount := c;
+    F.AllowSelect := True;
+    if F.ShowModal = mrOk then
+      edtSellerAcc.Text := TAccountComp.AccountNumberToAccountTxtNumber(F.GetSelected);
+  finally
+    F.Free;
+  end;
+end;
+
+
+procedure TWIZEnlistAccountForSale_EnterSeller.OnNext;
+var
+  c: cardinal;
+  aa: TAccount;
+begin
+  TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAcc.Text, c);
+  Model.SendPASC.DestinationAccount := TNode.Node.Operations.SafeBoxTransaction.account(c);
+end;
+
+function TWIZEnlistAccountForSale_EnterSeller.Validate(out message: ansistring): boolean;
+var
+  i: integer;
+  c: cardinal;
+begin
+  Result := True;
+
+  if not (TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAcc.Text, c)) then
+  begin
+    message := 'Invalid seller account (' + edtSellerAcc.Text + ')';
+    Result := False;
+    Exit;
+  end;
+
+  if (c < 0) or (c >= TNode.Node.Bank.AccountsCount) then
+  begin
+    message := 'Invalid seller account (' +
+      TAccountComp.AccountNumberToAccountTxtNumber(c) + ')';
+    Result := False;
+    Exit;
+  end;
+
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+    if (Model.Account.SelectedAccounts[i].Account = c) then
+    begin
+      message := 'Seller account cannot be same account';
+      Result := False;
+      Exit;
+    end;
+
+  Model.EnlistAccountForSale.SellerAccount := TNode.Node.Operations.SafeBoxTransaction.account(c);
+
+end;
+
+end.

+ 0 - 141
src/gui/wizards/operations/UWIZEnlistAccountForSale_List.pas

@@ -1,141 +0,0 @@
-unit UWIZEnlistAccountForSale_List;
-
-{$mode delphi}
-{$modeswitch nestedprocvars}
-
-{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
-
-  Distributed under the MIT software license, see the accompanying file LICENSE
-  or visit http://www.opensource.org/licenses/mit-license.php.
-}
-
-interface
-
-uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, UVisualGrid, UCommon.Data, UCellRenderers,
-  UWizard, UWIZEnlistAccountForSale, UWIZEnlistAccountForSale_Transaction, UWIZEnlistAccountForSale_PrivateSaleConfig,
-  UWIZEnlistAccountForSale_Confirmation;
-
-type
-
-  { TWIZEnlistAccountForSale_List }
-
-  TWIZEnlistAccountForSale_List = class(TWizardForm<TWIZEnlistAccountForSaleModel>)
-    grpEnlistAccountForSale: TGroupBox;
-    grpTransferAccount: TGroupBox;
-    paGrid: TPanel;
-  private
-    FSendersGrid: TVisualGrid;
-  public
-    procedure OnPresent; override;
-    procedure OnNext; override;
-    function Validate(out message: ansistring): boolean; override;
-  end;
-
-
-
-implementation
-
-{$R *.lfm}
-
-uses UAccounts, USettings, UDataSources, UCommon, UCommon.UI, Generics.Collections;
-
-type
-
-  { TAccountSenderDataSource }
-
-  TAccountSenderDataSource = class(TAccountsDataSourceBase)
-  private
-    FModel: TWIZEnlistAccountForSaleModel;
-  public
-    property Model: TWIZEnlistAccountForSaleModel read FModel write FModel;
-    procedure FetchAll(const AContainer: TList<TAccount>); override;
-  end;
-
-procedure TAccountSenderDataSource.FetchAll(const AContainer: TList<TAccount>);
-var
-  i: integer;
-begin
-  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
-  begin
-    AContainer.Add(Model.SelectedAccounts[i]);
-  end;
-end;
-
-{ TWIZEnlistAccountForSale_List }
-
-procedure TWIZEnlistAccountForSale_List.OnPresent;
-var
-  Data: TAccountSenderDataSource;
-begin
-  FSendersGrid := TVisualGrid.Create(Self);
-  FSendersGrid.CanSearch := False;
-  FSendersGrid.SortMode := smMultiColumn;
-  FSendersGrid.FetchDataInThread := False;
-  FSendersGrid.AutoPageSize := True;
-  FSendersGrid.SelectionType := stNone;
-  FSendersGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone,
-    vgoAutoHidePaging];
-  with FSendersGrid.AddColumn('Account') do
-  begin
-    StretchedToFill := True;
-    Binding := 'AccountNumber';
-    SortBinding := 'AccountNumber';
-    DisplayBinding := 'Account';
-    Width := 100;
-    HeaderFontStyles := [fsBold];
-    DataFontStyles := [fsBold];
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FSendersGrid.AddColumn('Balance') do
-  begin
-    Binding := 'BalanceDecimal';
-    SortBinding := 'Balance';
-    DisplayBinding := 'Balance';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  Data := TAccountSenderDataSource.Create(FSendersGrid);
-  Data.Model := Model;
-  FSendersGrid.DataSource := Data;
-  paGrid.AddControlDockCenter(FSendersGrid);
-end;
-
-procedure TWIZEnlistAccountForSale_List.OnNext;
-begin
-  case Model.AccountSaleMode of
-  akaPublicSale:
-    begin
-      UpdatePath(ptReplaceAllNext, [TWIZEnlistAccountForSale_Transaction, TWIZEnlistAccountForSale_Confirmation]);
-    end;
-
-   akaPrivateSale:
-    begin
-      UpdatePath(ptReplaceAllNext, [TWIZEnlistAccountForSale_PrivateSaleConfig, TWIZEnlistAccountForSale_Confirmation]);
-    end;
-
-  end;
-end;
-
-function TWIZEnlistAccountForSale_List.Validate(out message: ansistring): boolean;
-var
-  i: Integer;
-begin
-  Result := True;
-   for i := Low(model.SelectedAccounts) to High(model.SelectedAccounts) do
-  begin
-    if TAccountComp.IsAccountForSale(model.SelectedAccounts[i].accountInfo) then
-    begin
-      Result := False;
-      message := 'Account ' + TAccountComp.AccountNumberToAccountTxtNumber(
-        model.SelectedAccounts[i].account) + ' is already enlisted for sale';
-      Exit;
-    end;
-  end;
-end;
-
-end.

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

@@ -1,50 +0,0 @@
-object WIZEnlistAccountForSale_PrivateSaleConfig: TWIZEnlistAccountForSale_PrivateSaleConfig
-  Left = 0
-  Height = 253
-  Top = 40
-  Width = 429
-  Caption = 'WIZEnlistAccountForSale_PrivateSaleConfig'
-  ClientHeight = 253
-  ClientWidth = 429
-  Visible = False
-  object gbTransaction: TGroupBox
-    Left = 24
-    Height = 216
-    Top = 16
-    Width = 384
-    Caption = 'Private Sale Config'
-    ClientHeight = 196
-    ClientWidth = 380
-    TabOrder = 0
-    object lblBlockLock: TLabel
-      Left = 8
-      Height = 15
-      Top = 8
-      Width = 98
-      Caption = 'Locked Until Block'
-      ParentColor = False
-    end
-    object edtBlockLock: TEdit
-      Left = 8
-      Height = 23
-      Top = 40
-      Width = 360
-      TabOrder = 0
-    end
-    object lblPublicKey: TLabel
-      Left = 8
-      Height = 15
-      Top = 104
-      Width = 120
-      Caption = 'New Owner Public Key'
-      ParentColor = False
-    end
-    object edtPublicKey: TEdit
-      Left = 8
-      Height = 23
-      Top = 136
-      Width = 360
-      TabOrder = 1
-    end
-  end
-end

+ 0 - 92
src/gui/wizards/operations/UWIZEnlistAccountForSale_PrivateSaleConfig.pas

@@ -1,92 +0,0 @@
-unit UWIZEnlistAccountForSale_PrivateSaleConfig;
-
-{$mode delphi}
-{$modeswitch nestedprocvars}
-
-{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
-
-  Distributed under the MIT software license, see the accompanying file LICENSE
-  or visit http://www.opensource.org/licenses/mit-license.php.
-}
-
-interface
-
-uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, Buttons, UWizard, UWIZEnlistAccountForSale,
-  UWIZEnlistAccountForSale_Transaction,
-  UWIZEnlistAccountForSale_Confirmation;
-
-type
-
-  { TWIZEnlistAccountForSale_PrivateSaleConfig }
-
-  TWIZEnlistAccountForSale_PrivateSaleConfig =
-  class(TWizardForm<TWIZEnlistAccountForSaleModel>)
-    edtBlockLock: TEdit;
-    edtPublicKey: TEdit;
-    gbTransaction: TGroupBox;
-    lblBlockLock: TLabel;
-    lblPublicKey: TLabel;
-  public
-    procedure OnNext; override;
-    function Validate(out message: ansistring): boolean; override;
-  end;
-
-
-implementation
-
-{$R *.lfm}
-
-uses
-  UAccounts;
-
-{ TWIZEnlistAccountForSale_PrivateSaleConfig }
-
-procedure TWIZEnlistAccountForSale_PrivateSaleConfig.OnNext;
-begin
-  Model.NewPublicKey := edtPublicKey.Text;
-  UpdatePath(ptReplaceAllNext, [TWIZEnlistAccountForSale_Transaction,
-    TWIZEnlistAccountForSale_Confirmation]);
-end;
-
-function TWIZEnlistAccountForSale_PrivateSaleConfig.Validate(
-  out message: ansistring): boolean;
-var
-  c, LockedUntilBlock: cardinal;
-  i: integer;
-begin
-  Result := True;
-
-  LockedUntilBlock := StrToIntDef(edtBlockLock.Text, 0);
-  if LockedUntilBlock = 0 then
-  begin
-    message := 'Insert locking block';
-    Result := False;
-    exit;
-  end;
-  Model.LockedUntilBlock := LockedUntilBlock;
-
-  if not TAccountComp.AccountKeyFromImport(edtPublicKey.Text,
-    Model.NewOwnerPublicKey, message) then
-  begin
-    message := 'Public key: ' + message;
-    Result := False;
-    exit;
-
-  end;
-
-  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
-  begin
-    if TAccountComp.EqualAccountKeys(Model.NewOwnerPublicKey,
-      Model.SelectedAccounts[i].accountInfo.accountKey) then
-    begin
-      message := 'New public key for private sale is the same public key';
-      Result := False;
-      Exit;
-    end;
-  end;
-
-end;
-
-end.

+ 3 - 3
src/gui/wizards/operations/UWIZEnlistAccountForSale_Start.lfm → src/gui/wizards/operations/UWIZEnlistAccountForSale_SelectOption.lfm

@@ -1,10 +1,10 @@
-object WIZEnlistAccountForSale_Start: TWIZEnlistAccountForSale_Start
+object WIZEnlistAccountForSale_SelectOption: TWIZEnlistAccountForSale_SelectOption
   Left = 0
   Height = 253
   Top = 0
   Width = 429
   ActiveControl = rbPublicSale
-  Caption = 'WIZEnlistAccountForSale_Start'
+  Caption = 'WIZEnlistAccountForSale_SelectOption'
   ClientHeight = 253
   ClientWidth = 429
   Visible = False
@@ -59,7 +59,7 @@ object WIZEnlistAccountForSale_Start: TWIZEnlistAccountForSale_Start
     Width = 350
     Anchors = [akTop, akLeft, akRight]
     AutoSize = False
-    Caption = 'This account is only available to the specified public key for sale.'
+    Caption = 'This account is only available for sale to the specified public key.'
     ParentColor = False
     WordWrap = True
   end

+ 11 - 14
src/gui/wizards/operations/UWIZEnlistAccountForSale_Start.pas → src/gui/wizards/operations/UWIZEnlistAccountForSale_SelectOption.pas

@@ -1,4 +1,4 @@
-unit UWIZEnlistAccountForSale_Start;
+unit UWIZEnlistAccountForSale_SelectOption;
 
 {$mode delphi}
 {$modeswitch nestedprocvars}
@@ -13,14 +13,13 @@ interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, UWizard, UWIZEnlistAccountForSale, UWIZEnlistAccountForSale_List,
-  UWIZEnlistAccountForSale_Confirmation;
+  ExtCtrls, UWizard, UWIZModels, UWIZEnlistAccountForSale_EnterPublicKey;
 
 type
 
-  { TWIZEnlistAccountForSale_Start }
+  { TWIZEnlistAccountForSale_SelectOption }
 
-  TWIZEnlistAccountForSale_Start = class(TWizardForm<TWIZEnlistAccountForSaleModel>)
+  TWIZEnlistAccountForSale_SelectOption = class(TWizardForm<TWIZOperationsModel>)
     grpEnlistAccountForSale: TGroupBox;
     Label1: TLabel;
     Label2: TLabel;
@@ -39,20 +38,18 @@ implementation
 
 uses UAccounts, USettings, UDataSources, UCommon, UCommon.UI, Generics.Collections;
 
-{ TWIZEnlistAccountForSale_Start }
+{ TWIZEnlistAccountForSale_SelectOption }
 
-procedure TWIZEnlistAccountForSale_Start.OnNext;
+procedure TWIZEnlistAccountForSale_SelectOption.OnNext;
 begin
-  if rbPublicSale.Checked = True then
-  begin
-    Model.AccountSaleMode := akaPublicSale;
-  end
+  if rbPublicSale.Checked then
+    Model.EnlistAccountForSale.AccountSaleMode := akaPublicSale
   else
   begin
-    Model.AccountSaleMode := akaPrivateSale;
+    Model.EnlistAccountForSale.AccountSaleMode := akaPrivateSale;
+    UpdatePath(ptInject, [TWIZEnlistAccountForSale_EnterPublicKey]);
   end;
-  UpdatePath(ptReplaceAllNext, [TWIZEnlistAccountForSale_List,
-    TWIZEnlistAccountForSale_Confirmation]);
+
 end;
 
 end.

+ 0 - 199
src/gui/wizards/operations/UWIZEnlistAccountForSale_Transaction.pas

@@ -1,199 +0,0 @@
-unit UWIZEnlistAccountForSale_Transaction;
-
-{$mode delphi}
-{$modeswitch nestedprocvars}
-
-{ Copyright (c) 2018 by Ugochukwu Mmaduekwe
-
-  Distributed under the MIT software license, see the accompanying file LICENSE
-  or visit http://www.opensource.org/licenses/mit-license.php.
-}
-
-interface
-
-uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, Buttons, UCommon, UCommon.Collections, UWallet,
-  UFRMAccountSelect, UNode, UWizard, UWIZEnlistAccountForSale,
-  UWIZEnlistAccountForSale_TransactionPayload,
-  UWIZEnlistAccountForSale_Confirmation;
-
-type
-
-  { TWIZEnlistAccountForSale_Transaction }
-
-  TWIZEnlistAccountForSale_Transaction =
-    class(TWizardForm<TWIZEnlistAccountForSaleModel>)
-    btnSearch: TSpeedButton;
-    cbSignerAccount: TComboBox;
-    edtSalePrice: TEdit;
-    edtSellerAccount: TEdit;
-    edtOpFee: TEdit;
-    gbTransaction: TGroupBox;
-    lblBalance: TLabel;
-    lblSalePrice: TLabel;
-    lblSellerAccount: TLabel;
-    lblOpFee: TLabel;
-    lblTotalBalances: TLabel;
-    lblTotalBalanceValue: TLabel;
-    procedure btnSearchClick(Sender: TObject);
-    procedure cbSignerAccountChange(Sender: TObject);
-
-  public
-    procedure OnPresent; override;
-    procedure OnNext; override;
-    function Validate(out message: ansistring): boolean; override;
-  end;
-
-
-implementation
-
-{$R *.lfm}
-
-uses
-  UAccounts, UUserInterface, USettings;
-
-{ TWIZEnlistAccountForSale_Transaction }
-
-procedure TWIZEnlistAccountForSale_Transaction.cbSignerAccountChange(Sender: TObject);
-begin
-  if cbSignerAccount.ItemIndex < 1 then
-  begin
-    lblBalance.Font.Color := clRed;
-    lblBalance.Caption := 'Please Select Signer Account';
-  end
-  else
-  begin
-    lblBalance.Font.Color := clGreen;
-    lblBalance.Caption := Format('%s PASC',
-      [TAccountComp.FormatMoney(Model.SelectedAccounts[PtrInt(
-      cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])].Balance)]);
-  end;
-end;
-
-procedure TWIZEnlistAccountForSale_Transaction.btnSearchClick(Sender: TObject);
-var
-  F: TFRMAccountSelect;
-  c: cardinal;
-begin
-  F := TFRMAccountSelect.Create(Self);
-  F.Position := poMainFormCenter;
-  try
-    F.Node := TNode.Node;
-    F.WalletKeys := TWallet.Keys;
-    F.Filters := edtSellerAccount.Tag;
-    if TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAccount.Text, c) then
-      F.DefaultAccount := c;
-    F.AllowSelect := True;
-    if F.ShowModal = mrOk then
-    begin
-      edtSellerAccount.Text := TAccountComp.AccountNumberToAccountTxtNumber(F.GetSelected);
-    end;
-  finally
-    F.Free;
-  end;
-end;
-
-procedure TWIZEnlistAccountForSale_Transaction.OnPresent;
-
-  function GetAccNoWithChecksum(AAccountNumber: cardinal): string;
-  begin
-    Result := TAccountComp.AccountNumberToAccountTxtNumber(AAccountNumber);
-  end;
-
-var
-  acc: TAccount;
-  accNumberwithChecksum: string;
-  totalBalance: int64;
-  i: integer;
-begin
-  cbSignerAccount.Items.BeginUpdate;
-  totalBalance := 0;
-  try
-    cbSignerAccount.Items.Clear;
-    cbSignerAccount.Items.Add('Select Signer Account');
-    for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
-    begin
-      acc := Model.SelectedAccounts[i];
-      accNumberwithChecksum := GetAccNoWithChecksum(acc.account);
-      totalBalance := totalBalance + acc.balance;
-      cbSignerAccount.Items.AddObject(accNumberwithChecksum, TObject(i));
-    end;
-  finally
-    cbSignerAccount.Items.EndUpdate;
-  end;
-  cbSignerAccount.ItemIndex := Model.SelectedIndex;
-  cbSignerAccountChange(Self);
-  lblTotalBalanceValue.Caption :=
-    Format('%s PASC', [TAccountComp.FormatMoney(totalBalance)]);
-  edtOpFee.Text := TAccountComp.FormatMoney(TSettings.DefaultFee);
-  edtSalePrice.Text := TAccountComp.FormatMoney(0);
-end;
-
-procedure TWIZEnlistAccountForSale_Transaction.OnNext;
-begin
-  Model.SelectedIndex := cbSignerAccount.ItemIndex;
-  Model.SignerAccount := Model.SelectedAccounts[PtrInt(
-    cbSignerAccount.Items.Objects[cbSignerAccount.ItemIndex])];
-
-  UpdatePath(ptReplaceAllNext, [TWIZEnlistAccountForSale_TransactionPayload,
-    TWIZEnlistAccountForSale_Confirmation]);
-end;
-
-function TWIZEnlistAccountForSale_Transaction.Validate(out message: ansistring): boolean;
-var
-  c: cardinal;
-  i: integer;
-begin
-  Result := True;
-  if cbSignerAccount.ItemIndex < 1 then
-  begin
-    message := 'A signer account must be selected';
-    Result := False;
-    Exit;
-  end;
-
-  if not TAccountComp.TxtToMoney(edtSalePrice.Text, Model.SalePrice) then
-  begin
-    message := 'Invalid price (' + edtSalePrice.Text + ')';
-    Result := False;
-    Exit;
-  end;
-
-  if not (TAccountComp.AccountTxtNumberToAccountNumber(edtSellerAccount.Text, c)) then
-  begin
-    message := 'Invalid seller account (' + edtSellerAccount.Text + ')';
-    Result := False;
-    Exit;
-  end;
-
-  if (c < 0) or (c >= TNode.Node.Bank.AccountsCount) then
-  begin
-    message := 'Invalid seller account (' +
-      TAccountComp.AccountNumberToAccountTxtNumber(c) + ')';
-    Result := False;
-    Exit;
-  end;
-
-  for i := Low(Model.SelectedAccounts) to High(Model.SelectedAccounts) do
-  begin
-    if (Model.SelectedAccounts[i].Account = c) then
-    begin
-      message := 'Seller account cannot be same account';
-      Result := False;
-      Exit;
-    end;
-  end;
-
-  Model.SellerAccount := TNode.Node.Operations.SafeBoxTransaction.account(c);
-
-  if not TAccountComp.TxtToMoney(Trim(edtOpFee.Text), Model.Fee.DefaultFee) then
-  begin
-    message := 'Invalid fee value "' + edtOpFee.Text + '"';
-    Result := False;
-    Exit;
-  end;
-
-end;
-
-end.

+ 0 - 98
src/gui/wizards/operations/UWIZEnlistAccountForSale_TransactionPayload.lfm

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

+ 0 - 82
src/gui/wizards/operations/UWIZEnlistAccountForSale_TransactionPayload.pas

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

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

@@ -7,6 +7,7 @@ object WIZOperationFee_Custom: TWIZOperationFee_Custom
   Caption = 'WIZOperationFee_Custom'
   ClientHeight = 253
   ClientWidth = 429
+  LCLVersion = '1.8.2.0'
   Visible = False
   object gbTransactionFee: TGroupBox
     Left = 14

+ 26 - 6
src/gui/wizards/operations/UWIZOperationFee_Custom.pas

@@ -38,6 +38,7 @@ type
 
 
 
+
   public
     procedure OnPresent; override;
     procedure OnNext; override;
@@ -75,8 +76,8 @@ end;
 
 procedure TWIZOperationFee_Custom.OnNext;
 begin
-  TAccountComp.TxtToMoney(Trim(fseFee.ValueToStr(fseFee.Value)),
-    Model.Fee.SingleOperationFee);
+  //TAccountComp.TxtToMoney(Trim(fseFee.ValueToStr(fseFee.Value)),
+  //  Model.Fee.SingleOperationFee);
   if Model.Payload.HasPayload then
     UpdatePath(ptInject, [TWIZOperationPayload_Encryption])
   else if Length(Model.Account.SelectedAccounts) > 1 then
@@ -91,6 +92,8 @@ end;
 function TWIZOperationFee_Custom.Validate(out message: ansistring): boolean;
 var
   opfee: int64;
+  i: integer;
+  acc: TAccount;
 begin
   Result := True;
 
@@ -101,11 +104,28 @@ begin
     Exit;
   end;
 
-  if (opfee = 0) and (Length(Model.Account.SelectedAccounts) > 1) then
+  Model.Fee.SingleOperationFee := opfee;
+
+   if Length(Model.Account.SelectedAccounts) > 1 then
   begin
-    message := 'zero fee only allowed for single operations.';
-    Result := False;
-    Exit;
+    if not (Model.Fee.SingleOperationFee > 0) then
+    begin
+      message := 'zero fee only allowed for single operations.';
+      Result := False;
+      Exit;
+    end;
+  end;
+
+
+  for i := Low(Model.Account.SelectedAccounts) to High(Model.Account.SelectedAccounts) do
+  begin
+    acc := Model.Account.SelectedAccounts[i];
+    if acc.balance < Model.Fee.SingleOperationFee then
+    begin
+      message := 'Insufficient funds for fees in one or more accounts';
+      Result := False;
+      Exit;
+    end;
   end;
 end;
 

+ 0 - 36
src/gui/wizards/operations/UWIZOperationPayload_Encryption.lrs

@@ -1,36 +0,0 @@
-{ This is an automatically generated lazarus resource file }
-
-LazarusResources.Add('TWIZPayloadOverride','FORMDATA',[
-  'TPF0'#19'TWIZPayloadOverride'#18'WIZPayloadOverride'#4'Left'#2#0#6'Height'#3
-  +#253#0#3'Top'#2#0#5'Width'#3#173#1#13'ActiveControl'#7#21'rbEncryptedWithSen'
-  +'der'#7'Caption'#6#5'Form1'#12'ClientHeight'#3#253#0#11'ClientWidth'#3#173#1
-  +#10'LCLVersion'#6#7'1.8.2.0'#7'Visible'#8#0#9'TGroupBox'#10'grpPayload'#4'Le'
-  +'ft'#2#8#6'Height'#3#244#0#3'Top'#2#2#5'Width'#3#160#1#7'Anchors'#11#5'akTop'
-  +#6'akLeft'#7'akRight'#8'akBottom'#0#7'Caption'#6#19'Transaction Payload'#12
-  +'ClientHeight'#3#224#0#11'ClientWidth'#3#156#1#8'TabOrder'#2#0#0#6'TPanel'#9
-  +'paPayload'#4'Left'#2#8#6'Height'#3#214#0#3'Top'#2#2#5'Width'#3#140#1#7'Anch'
-  +'ors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#10'BevelOuter'#7#6'bvNo'
-  +'ne'#12'ClientHeight'#3#214#0#11'ClientWidth'#3#140#1#8'TabOrder'#2#0#0#12'T'
-  +'RadioButton'#24'rbEncryptedWithRecipient'#4'Left'#2#3#6'Height'#2#19#3'Top'
-  +#2'@'#5'Width'#3#156#0#7'Caption'#6#26'Encrypt with recipient key'#8'TabOrde'
-  +'r'#2#0#0#0#12'TRadioButton'#21'rbEncryptedWithSender'#4'Left'#2#3#6'Height'
-  +#2#19#3'Top'#2'p'#5'Width'#3#145#0#7'Caption'#6#23'Encrypt with sender key'#7
-  +'Checked'#9#8'TabOrder'#2#1#7'TabStop'#9#0#0#12'TRadioButton'#23'rbEncrypted'
-  +'WithPassword'#4'Left'#2#3#6'Height'#2#19#3'Top'#3#176#0#5'Width'#3#139#0#7
-  +'Caption'#6#21'Encrypt with password'#8'TabOrder'#2#2#0#0#12'TRadioButton'#14
-  +'rbNotEncrypted'#4'Left'#2#3#6'Height'#2#19#3'Top'#2#24#5'Width'#2'`'#7'Capt'
-  +'ion'#6#13'No Encryption'#8'TabOrder'#2#3#0#0#6'TLabel'#8'lblNote1'#4'Left'#2
-  +#3#6'Height'#2#15#3'Top'#2#3#5'Width'#3'W'#1#7'Caption'#6'@What type of payl'
-  +'oad would you like to attach to your operation?'#11'ParentColor'#8#0#0#6'TL'
-  +'abel'#15'lblNoEncryption'#4'Left'#2#19#6'Height'#2#15#3'Top'#2'.'#5'Width'#3
-  +'n'#1#7'Caption'#6'FUse this option to specify a publicly visible message an'
-  +'yone can view.'#11'ParentColor'#8#0#0#6'TLabel'#16'lblNoEncryption1'#4'Left'
-  +#2#19#6'Height'#2#15#3'Top'#2'X'#5'Width'#3'u'#1#7'Caption'#6'GUse this opti'
-  +'on to specify a message which only the recipient can view.'#11'ParentColor'
-  +#8#0#0#6'TLabel'#16'lblNoEncryption2'#4'Left'#2#19#6'Height'#2#30#3'Top'#3
-  +#136#0#5'Width'#3'y'#1#7'Caption'#6'~Only you will be able to decrypt this m'
-  +'essage. This is useful for tagging '#13#10'transactions for your own record'
-  +' keeping purposes.'#11'ParentColor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#19#6
-  +'Height'#2#15#3'Top'#3#198#0#5'Width'#3'9'#1#7'Caption'#6';Only those with p'
-  +'assword will be able to view this message.'#11'ParentColor'#8#0#0#0#0#0
-]);

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

@@ -105,6 +105,7 @@ end;
 function TWIZSendPASCWizard.UpdateOpTransaction(const SenderAccount: TAccount; var DestAccount: TAccount; var amount: int64; var errors: string): boolean;
 var
   c: cardinal;
+  i: integer;
 begin
   Result := False;
   errors := '';

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

@@ -6,6 +6,7 @@ object WIZSendPASC_Confirmation: TWIZSendPASC_Confirmation
   Caption = 'WIZSendPASC_Confirmation'
   ClientHeight = 320
   ClientWidth = 511
+  LCLVersion = '1.8.2.0'
   Visible = False
   object GroupBox1: TGroupBox
     Left = 10

+ 0 - 15
src/gui/wizards/operations/UWIZSendPASC_Confirmation.pas

@@ -37,7 +37,6 @@ type
   public
     procedure OnPresent; override;
     procedure OnNext; override;
-    function Validate(out message: ansistring): boolean; override;
   end;
 
 
@@ -121,20 +120,6 @@ begin
   end;
 end;
 
-function TWIZSendPASC_Confirmation.Validate(out message: ansistring): boolean;
-begin
-  Result := True;
-  if Length(Model.Account.SelectedAccounts) > 1 then
-  begin
-    if not (Model.Fee.SingleOperationFee > 0) then
-    begin
-      message := 'insufficient fee for total operation.';
-      Result := False;
-      Exit;
-    end;
-  end;
-end;
-
 { TAccountSenderDataSource }
 
 function TAccountSenderDataSource.GetColumns: TDataColumns;

+ 61 - 44
src/pascalcoin_wallet.lpi

@@ -33,7 +33,7 @@
         <PackageName Value="LCL"/>
       </Item1>
     </RequiredPackages>
-    <Units Count="98">
+    <Units Count="99">
       <Unit0>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <IsPartOfProject Value="True"/>
@@ -346,7 +346,7 @@
         <IsPartOfProject Value="True"/>
       </Unit62>
       <Unit63>
-        <Filename Value="core.utils\UCoreObjects.pas"/>
+        <Filename Value="core.utils\UCoreUtils.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit63>
       <Unit64>
@@ -410,149 +410,166 @@
       <Unit74>
         <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZEnlistAccountForSale_Confirmation"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit74>
       <Unit75>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_List.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZOperationFee_Custom.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZOperationFee_Custom"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit75>
       <Unit76>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_PrivateSaleConfig.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Content.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZOperationPayload_Content"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit76>
       <Unit77>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Start.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Encryption.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZOperationPayload_Encryption"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit77>
       <Unit78>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_Transaction.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Password.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZEnlistAccountForSale_Transaction"/>
+        <ComponentName Value="WIZOperationPayload_Password"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit78>
       <Unit79>
-        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_TransactionPayload.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZOperationSigner_Select.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZOperationSigner_Select"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit79>
       <Unit80>
-        <Filename Value="gui\wizards\operations\UWIZOperationFee_Custom.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZOperationFee_Custom"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit80>
       <Unit81>
-        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Content.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZOperationPayload_Content"/>
+        <ComponentName Value="WIZSendPASC_Confirmation"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit81>
       <Unit82>
-        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Encryption.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_ConfirmSender.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZOperationPayload_Encryption"/>
+        <ComponentName Value="WIZSendPASC_ConfirmSender"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit82>
       <Unit83>
-        <Filename Value="gui\wizards\operations\UWIZOperationPayload_Password.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterQuantity.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZOperationPayload_Password"/>
+        <ComponentName Value="WIZSendPASC_EnterQuantity"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit83>
       <Unit84>
-        <Filename Value="gui\wizards\operations\UWIZOperationSigner_Select.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterRecipient.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZOperationSigner_Select"/>
+        <ComponentName Value="WIZSendPASC_EnterRecipient"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit84>
       <Unit85>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit85>
       <Unit86>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectOption.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_Confirmation"/>
+        <ComponentName Value="WIZChangeKey_SelectOption"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit86>
       <Unit87>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_ConfirmSender.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_EnterKey.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_ConfirmSender"/>
+        <ComponentName Value="WIZChangeKey_EnterKey"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit87>
       <Unit88>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterQuantity.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectKey.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_EnterQuantity"/>
+        <ComponentName Value="WIZChangeKey_SelectKey"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit88>
       <Unit89>
-        <Filename Value="gui\wizards\operations\UWIZSendPASC_EnterRecipient.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_ConfirmAccount.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZSendPASC_EnterRecipient"/>
+        <ComponentName Value="WIZChangeKey_ConfirmAccount"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit89>
       <Unit90>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZChangeKey_Confirmation.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZChangeKey_Confirmation"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit90>
       <Unit91>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectOption.pas"/>
+        <Filename Value="gui-classic\UGridUtils.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeKey_SelectOption"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit91>
       <Unit92>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey_EnterKey.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_EnterSeller.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeKey_EnterKey"/>
+        <ComponentName Value="WIZEnlistAccountForSale_EnterSeller"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit92>
       <Unit93>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey_SelectKey.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_EnterSaleAmount.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeKey_SelectKey"/>
+        <ComponentName Value="WIZEnlistAccountForSale_EnterSaleAmount"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit93>
       <Unit94>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey_ConfirmAccount.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_SelectOption.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeKey_ConfirmAccount"/>
+        <ComponentName Value="WIZEnlistAccountForSale_SelectOption"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit94>
       <Unit95>
-        <Filename Value="gui\wizards\operations\UWIZChangeKey_Confirmation.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_EnterLockingBlock.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="WIZChangeKey_Confirmation"/>
+        <ComponentName Value="WIZEnlistAccountForSale_EnterLockingBlock"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit95>
       <Unit96>
-        <Filename Value="gui-classic\UGridUtils.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_EnterPublicKey.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZEnlistAccountForSale_EnterPublicKey"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit96>
       <Unit97>
-        <Filename Value="core.utils\UCoreUtils.pas"/>
+        <Filename Value="gui\wizards\operations\UWIZEnlistAccountForSale_ConfirmAccount.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZEnlistAccountForSale_ConfirmAccount"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit97>
+      <Unit98>
+        <Filename Value="core.utils\UCoreObjects.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit98>
     </Units>
   </ProjectOptions>
   <CompilerOptions>