Browse Source

New GUI: minor refactoring

Herman Schoenfeld 6 years ago
parent
commit
6230296174

+ 1 - 2
src/gui-experimental/UFRMExecuteOperations.pas

@@ -11,8 +11,7 @@ unit UFRMExecuteOperations;
   Source: https://github.com/PascalCoin/PascalCoin
 
   Acknowledgements:
-  - Ugochukwu Mmaduekwe - main developer
-  - Herman Schoenfeld - designer
+  - Herman Schoenfeld - developer
 
   THIS LICENSE HEADER MUST NOT BE REMOVED.
 }

+ 643 - 4
src/gui-experimental/core.utils/UCoreUtils.pas

@@ -22,8 +22,10 @@ unit UCoreUtils;
 interface
 
 uses
-  Classes, SysUtils, UCrypto, UAccounts, UBlockChain, UOpTransaction, UNode, UCommon, UNetProtocol,
-  Generics.Collections, Generics.Defaults, UCoreObjects, Forms, Dialogs, LCLType, UCellRenderers, UCommon.Collections;
+  Classes, SysUtils, UCrypto, UAccounts, UBlockChain, UOpTransaction, UNode,
+  UBaseTypes, UCommon, UNetProtocol, UCoreObjects,UCommon.Collections,
+  Generics.Collections, Generics.Defaults,
+  Forms, Dialogs, LCLType, UCellRenderers;
 
 type
 
@@ -107,10 +109,23 @@ type
     function TotalBlockCount : Integer;
   end;
 
+  { TWIZOperationsHelper }
+
+  TWIZOperationsHelper = class
+  private
+    class function UpdatePayload(const ASenderPublicKey, ADestinationPublicKey: TAccountKey; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent: string; var AEncodedPayloadBytes: TRawBytes; const APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
+    class function SendPASCFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalAmount, ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean; static;
+    class function OthersFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean; static;
+  public
+    class function ExecuteSendPASC(const ASelectedAccounts: TArray<TAccount>; const ADestinationAccount, ASignerAccount: TAccount; AAmount, AFee: int64; const ASendPASCMode: TSendPASCMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
+    class function ExecuteChangeKey(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount: TAccount; APublicKey: TAccountKey; AFee: int64; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
+    class function ExecuteEnlistAccountForSale(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount, ASellerAccount: TAccount; const APublicKey: TAccountKey; AFee, ASalePrice: int64; ALockedUntilBlock: UInt32; const AAccountSaleMode: TAccountSaleMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
+  end;
+
 implementation
 
 uses
-  UMemory, UConst, UWallet, UECIES, UAES, ULog;
+  UMemory, UConst, UWallet, UUserInterface, UECIES, UAES, ULog;
 
 { TCoreTool }
 
@@ -248,7 +263,6 @@ begin
   Result := LAccs.ToArray;
 end;
 
-
 { TNodeHelper }
 
 function TNodeHelper.HasBestKnownBlockchainTip: boolean;
@@ -605,4 +619,629 @@ begin
   Result := Round(Self.TotalSeconds / CT_NewLineSecondsAvg);
 end;
 
+{ TWIZOperationsHelper }
+
+class function TWIZOperationsHelper.SendPASCFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalAmount, ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean;
+var
+  LAuxs, LOperationsTxt: string;
+  i: integer;
+begin
+  LOperationsTxt := AOperationsTxt;
+  if (ANoOfOperations > 1) then
+  begin
+    LAuxs := 'Total amount that dest will receive: ' + TAccountComp.FormatMoney(
+      ATotalAmount) + #10;
+    if Application.MessageBox(
+      PChar('Execute ' + IntToStr(ANoOfOperations) +
+      ' operations?' + #10 + 'Operation: ' + LOperationsTxt + #10 +
+      LAuxs + 'Total fee: ' + TAccountComp.FormatMoney(ATotalFee) +
+      #10 + #10 + 'Note: This operation will be transmitted to the network!'),
+      PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+      idYes then
+      Exit;
+  end
+  else
+  if Application.MessageBox(PChar('Execute this operation:' +
+    #10 + #10 + AOperationToString + #10 + #10 +
+    'Note: This operation will be transmitted to the network!'),
+    PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+    idYes then
+    Exit;
+  Result := True;
+  i := TNode.Node.AddOperations(nil, AOperationsHashTree, nil, AErrorMessage);
+  if (i = AOperationsHashTree.OperationsCount) then
+  begin
+    LOperationsTxt := 'Successfully executed ' + IntToStr(i) +
+      ' operations!' + #10 + #10 + AOperationToString;
+    if i > 1 then
+      ShowMessage(LOperationsTxt)
+    else
+    begin
+      Application.MessageBox(
+        PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
+        #10 + #10 + AOperationToString),
+        PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
+    end;
+  end
+  else if (i > 0) then
+  begin
+    LOperationsTxt := 'One or more of your operations has not been executed:' +
+      #10 + 'Errors:' + #10 + AErrorMessage + #10 + #10 +
+      'Total successfully executed operations: ' + IntToStr(i);
+    ShowMessage(LOperationsTxt);
+  end
+  else
+    Result := False;
+end;
+
+class function TWIZOperationsHelper.UpdatePayload(const ASenderPublicKey, ADestinationPublicKey: TAccountKey; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent: string; var AEncodedPayloadBytes: TRawBytes; const APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
+var
+  LValid: boolean;
+begin
+
+  if (APayloadContent = '') then
+    Exit(True);
+
+  LValid := False;
+  AErrorMessage := 'An Error Occured During Payload Encryption.';
+
+  try
+
+    case APayloadEncryptionMode of
+
+      pemEncryptWithSender:
+      begin
+        // Use sender public key
+        AEncodedPayloadBytes := ECIESEncrypt(ASenderPublicKey, APayloadContent);
+        LValid := AEncodedPayloadBytes <> '';
+      end;
+
+      pemEncryptWithReceiver:
+      begin
+        // With destination public key
+        AEncodedPayloadBytes := ECIESEncrypt(ADestinationPublicKey, APayloadContent);
+        LValid := AEncodedPayloadBytes <> '';
+      end;
+
+      pemEncryptWithPassword:
+      begin
+        // With defined password
+        if APayloadEncryptionPassword = '' then
+        begin
+          AErrorMessage := 'Payload Encryption Password Cannot Be Empty With The Chosen Option : "Encrypt With Password."';
+          Exit(False);
+        end;
+        AEncodedPayloadBytes := TAESComp.EVP_Encrypt_AES256(
+          APayloadContent, APayloadEncryptionPassword);
+        LValid := AEncodedPayloadBytes <> '';
+      end;
+
+      pemNotEncrypt:
+      begin
+        // no encryption
+        AEncodedPayloadBytes := APayloadContent;
+        LValid := True;
+      end
+
+      else
+      begin
+        AErrorMessage := 'Unknown Encryption Selected';
+        Exit(False);
+      end;
+    end;
+
+  finally
+    if LValid then
+      if Length(AEncodedPayloadBytes) > CT_MaxPayloadSize then
+      begin
+        LValid := False;
+        AErrorMessage := Format('Payload Size Is %d Which Is Bigger Than %d', [Length(AEncodedPayloadBytes), CT_MaxPayloadSize]);
+      end;
+    Result := LValid;
+  end;
+end;
+
+class function TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean;
+var
+  LAuxs, LOperationsTxt: string;
+  i: integer;
+begin
+  LOperationsTxt := AOperationsTxt;
+  if (ANoOfOperations > 1) then
+  begin
+    LAuxs := '';
+    if Application.MessageBox(
+      PChar('Execute ' + IntToStr(ANoOfOperations) +
+      ' operations?' + #10 + 'Operation: ' + LOperationsTxt + #10 +
+      LAuxs + 'Total fee: ' + TAccountComp.FormatMoney(ATotalFee) +
+      #10 + #10 + 'Note: This operation will be transmitted to the network!'),
+      PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+      idYes then
+      Exit;
+  end
+  else
+  if Application.MessageBox(PChar('Execute this operation:' +
+    #10 + #10 + AOperationToString + #10 + #10 +
+    'Note: This operation will be transmitted to the network!'),
+    PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
+    idYes then
+    Exit;
+  Result := True;
+  i := TNode.Node.AddOperations(nil, AOperationsHashTree, nil, AErrorMessage);
+  if (i = AOperationsHashTree.OperationsCount) then
+  begin
+    LOperationsTxt := 'Successfully executed ' + IntToStr(i) +
+      ' operations!' + #10 + #10 + AOperationToString;
+    if i > 1 then
+      ShowMessage(LOperationsTxt)
+    else
+    begin
+      Application.MessageBox(
+        PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
+        #10 + #10 + AOperationToString),
+        PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
+    end;
+  end
+  else if (i > 0) then
+  begin
+    LOperationsTxt := 'One or more of your operations has not been executed:' +
+      #10 + 'Errors:' + #10 + AErrorMessage + #10 + #10 +
+      'Total successfully executed operations: ' + IntToStr(i);
+    ShowMessage(LOperationsTxt);
+  end
+  else
+    Result := False;
+end;
+
+class function TWIZOperationsHelper.ExecuteSendPASC(const ASelectedAccounts: TArray<TAccount>; const ADestinationAccount, ASignerAccount: TAccount; AAmount, AFee: int64; const ASendPASCMode: TSendPASCMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
+var
+  LWalletKey: TWalletKey;
+  LWalletKeys: TWalletKeys;
+  LNode: TNode;
+  LPCOperation: TPCOperation;
+  LOperationsHashTree: TOperationsHashTree;
+  LTotalAmount, LTotalSignerFee, LAmount, LFee: int64;
+  LDoOperation: boolean;
+  LOperationsTxt, LOperationToString: string;
+  LIdx, LAccountIdx, LNoOfOperations: integer;
+  LCurrentAccount: TAccount;
+  LPayloadEncodedBytes: TRawBytes;
+begin
+  if Length(ASelectedAccounts) = 0 then
+  begin
+    AErrorMessage := 'No Selected Account Found';
+    Exit(False);
+  end;
+
+  LWalletKeys := TWallet.Keys;
+  LNode := TNode.Node;
+
+  if not Assigned(LWalletKeys) then
+  begin
+    AErrorMessage := 'No Wallet Keys Found';
+    Exit(False);
+  end;
+
+  if not Assigned(LNode) then
+  begin
+    AErrorMessage := 'No Node Found';
+    Exit(False);
+  end;
+
+  LOperationsHashTree := TOperationsHashTree.Create;
+  try
+    LTotalAmount := 0;
+    LTotalSignerFee := 0;
+    LNoOfOperations := 0;
+    LOperationsTxt := '';
+    LOperationToString := '';
+    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
+    begin
+      LPCOperation := nil; // reset LPCOperation to Nil
+      LCurrentAccount := ASelectedAccounts[LAccountIdx];
+
+      if LCurrentAccount.account = ADestinationAccount.account then
+      begin
+        AErrorMessage := Format('Sender "%s" And Destination "%s" Accounts Are The Same', [LCurrentAccount.AccountString, ADestinationAccount.AccountString]);
+        Exit(False);
+      end;
+
+      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, ADestinationAccount.accountInfo.accountKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
+      begin
+        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
+        Exit(False);
+      end;
+
+      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
+      if LIdx < 0 then
+      begin
+        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+      LWalletKey := LWalletKeys.Key[LIdx];
+
+      if not Assigned(LWalletKey.PrivateKey) then
+      begin
+        if LWalletKey.HasPrivateKey then
+          AErrorMessage := 'Wallet is Password Protected. Please Unlock Before You Proceed.'
+        else
+          AErrorMessage := Format('Only Public Key of Account %s Was Found in Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+
+      LDoOperation := True;
+
+      if LCurrentAccount.balance > 0 then
+        case ASendPASCMode of
+          akaAllBalance:
+          begin
+            LAmount := LCurrentAccount.balance - AFee;
+            LFee := AFee;
+          end;
+
+          akaSpecifiedAmount:
+            if LCurrentAccount.balance >= UInt64(AAmount + AFee) then
+            begin
+              LAmount := AAmount;
+              LFee := AFee;
+            end
+            else
+            begin
+              AErrorMessage := Format('Insufficient Funds In "%s". %s < (%s + %s = %s)', [LCurrentAccount.AccountString, TAccountComp.FormatMoney(LCurrentAccount.balance), TAccountComp.FormatMoney(AAmount), TAccountComp.FormatMoney(AFee), TAccountComp.FormatMoney(AAmount + AFee)]);
+              Exit(False);
+            end;
+        end
+      else
+        LDoOperation := False;
+
+      if LDoOperation then
+      begin
+        LPCOperation := TOpTransaction.CreateTransaction(
+           TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation + 1, ADestinationAccount.account, LWalletKey.PrivateKey, LAmount, LFee, LPayloadEncodedBytes);
+        try
+          LOperationsTxt := Format('Transaction To "%s"', [ADestinationAccount.AccountString]);
+
+          if Assigned(LPCOperation) then
+          begin
+            LOperationsHashTree.AddOperationToHashTree(LPCOperation);
+            Inc(LTotalAmount, LAmount);
+            Inc(LTotalSignerFee, LFee);
+            Inc(LNoOfOperations);
+            if LOperationToString <> '' then
+              LOperationToString := LOperationToString + #10;
+            LOperationToString := LOperationToString + LPCOperation.ToString;
+          end;
+        finally
+          FreeAndNil(LPCOperation);
+        end;
+      end;
+
+    end;
+    if (LOperationsHashTree.OperationsCount = 0) then
+    begin
+      AErrorMessage := 'No Valid Operation To Execute';
+      Exit(False);
+    end;
+
+    Exit(TWIZOperationsHelper.SendPASCFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalAmount, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
+  finally
+    LOperationsHashTree.Free;
+  end;
+
+end;
+
+class function TWIZOperationsHelper.ExecuteChangeKey(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount: TAccount; APublicKey: TAccountKey; AFee: int64; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
+var
+  LWalletKey: TWalletKey;
+  LWalletKeys: TWalletKeys;
+  LNode: TNode;
+  LPCOperation: TPCOperation;
+  LOperationsHashTree: TOperationsHashTree;
+  LTotalSignerFee, LFee: int64;
+  LIsV2: boolean;
+  LOperationsTxt, LOperationToString: string;
+  LIdx, LAccountIdx, LNoOfOperations: integer;
+  LCurrentAccount, LSignerAccount: TAccount;
+  LPayloadEncodedBytes: TRawBytes;
+label
+  loop_start;
+begin
+  if Length(ASelectedAccounts) = 0 then
+  begin
+    AErrorMessage := 'No Selected Account Found';
+    Exit(False);
+  end;
+
+  LWalletKeys := TWallet.Keys;
+  LNode := TNode.Node;
+
+  if not Assigned(LWalletKeys) then
+  begin
+    AErrorMessage := 'No Wallet Keys Found';
+    Exit(False);
+  end;
+
+  if not Assigned(LNode) then
+  begin
+    AErrorMessage := 'No Node Found';
+    Exit(False);
+  end;
+
+  LOperationsHashTree := TOperationsHashTree.Create;
+  try
+    LIsV2 := LNode.Bank.SafeBox.CurrentProtocol >= CT_PROTOCOL_2;
+    LTotalSignerFee := 0;
+    LNoOfOperations := 0;
+    LOperationsTxt := '';
+    LOperationToString := '';
+    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
+    begin
+      loop_start:
+        LPCOperation := nil; // reset LPCOperation to Nil
+      LCurrentAccount := ASelectedAccounts[LAccountIdx];
+
+      if (TAccountComp.EqualAccountKeys(LCurrentAccount.accountInfo.accountKey,
+        APublicKey)) then
+      begin
+        AErrorMessage := 'New Key Is Same As Current Key';
+        Exit(False);
+      end;
+
+      if LNode.Bank.SafeBox.CurrentProtocol >= 1 then
+      begin
+        // Signer:
+        LSignerAccount := ASignerAccount;
+        if (TAccountComp.IsAccountLocked(LSignerAccount.accountInfo,
+          LNode.Bank.BlocksCount)) then
+        begin
+          AErrorMessage := Format('Signer Account "%s"  Is Locked Until Block %u', [LSignerAccount.AccountString, LSignerAccount.accountInfo.locked_until_block]);
+          Exit(False);
+        end;
+        if (not TAccountComp.EqualAccountKeys(
+          LSignerAccount.accountInfo.accountKey, LCurrentAccount.accountInfo.accountKey)) then
+        begin
+          AErrorMessage := Format('Signer Account %s Is Not The Owner Of Account %s', [LSignerAccount.AccountString, LCurrentAccount.AccountString]);
+          Exit(False);
+        end;
+      end
+      else
+        LSignerAccount := LCurrentAccount;
+
+      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, APublicKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
+      begin
+        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
+        Exit(False);
+      end;
+
+      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
+      if LIdx < 0 then
+      begin
+        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+      LWalletKey := LWalletKeys.Key[LIdx];
+
+      if not Assigned(LWalletKey.PrivateKey) then
+      begin
+        if LWalletKey.HasPrivateKey then
+          AErrorMessage := 'Wallet Is Password Protected. Please Unlock Before You Proceed.'
+        else
+          AErrorMessage := Format('Only Public Key of Account %s Was Found In Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+
+      if LIsV2 then
+      begin
+        // must ensure is Signer account last if included in sender accounts (not necessarily ordered enumeration)
+        if (LAccountIdx < Length(ASelectedAccounts) - 1) and
+          (LCurrentAccount.account = LSignerAccount.account) then
+        begin
+          TArrayTool<TAccount>.Swap(ASelectedAccounts, LAccountIdx,
+            Length(ASelectedAccounts) - 1); // ensure signer account processed last
+          goto loop_start; // TODO: remove ugly hack with refactoring!
+        end;
+
+        // Maintain correct signer fee distribution
+        if Uint64(LTotalSignerFee) >= LSignerAccount.balance then
+          LFee := 0
+        else if LSignerAccount.balance - uint64(LTotalSignerFee) >
+          UInt64(AFee) then
+          LFee := AFee
+        else
+          LFee := LSignerAccount.balance - UInt64(LTotalSignerFee);
+        LPCOperation := TOpChangeKeySigned.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LSignerAccount.account,
+          LSignerAccount.n_operation + LNoOfOperations + 1, LCurrentAccount.account,
+          LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
+      end
+      else
+        LPCOperation := TOpChangeKey.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation +
+          1, LCurrentAccount.account, LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
+
+      try
+        LOperationsTxt := Format('Change Key To "%s"', [TAccountComp.GetECInfoTxt(APublicKey.EC_OpenSSL_NID)]);
+        if Assigned(LPCOperation) then
+        begin
+          LOperationsHashTree.AddOperationToHashTree(LPCOperation);
+          Inc(LNoOfOperations);
+          Inc(LTotalSignerFee, LFee);
+          if LOperationToString <> '' then
+            LOperationToString := LOperationToString + #10;
+          LOperationToString := LOperationToString + LPCOperation.ToString;
+        end;
+      finally
+        FreeAndNil(LPCOperation);
+      end;
+
+    end;
+
+    if (LOperationsHashTree.OperationsCount = 0) then
+    begin
+      AErrorMessage := 'No Valid Operation to Execute';
+      Exit(False);
+    end;
+
+    Exit(TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
+  finally
+    LOperationsHashTree.Free;
+  end;
+
+end;
+
+class function TWIZOperationsHelper.ExecuteEnlistAccountForSale(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount, ASellerAccount: TAccount; const APublicKey: TAccountKey; AFee, ASalePrice: int64; ALockedUntilBlock: UInt32; const AAccountSaleMode: TAccountSaleMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
+var
+  LWalletKey: TWalletKey;
+  LWalletKeys: TWalletKeys;
+  LNode: TNode;
+  LPCOperation: TPCOperation;
+  LOperationsHashTree: TOperationsHashTree;
+  LTotalSignerFee, LFee: int64;
+  LOperationsTxt, LOperationToString: string;
+  LIdx, LAccountIdx, LNoOfOperations: integer;
+  LCurrentAccount, LSignerAccount: TAccount;
+  LPayloadEncodedBytes: TRawBytes;
+begin
+  if Length(ASelectedAccounts) = 0 then
+  begin
+    AErrorMessage := 'No Selected Account Found';
+    Exit(False);
+  end;
+
+  LWalletKeys := TWallet.Keys;
+  LNode := TNode.Node;
+
+  if not Assigned(LWalletKeys) then
+  begin
+    AErrorMessage := 'No Wallet Keys Found';
+    Exit(False);
+  end;
+
+  if not Assigned(LNode) then
+  begin
+    AErrorMessage := 'No Node Found';
+    Exit(False);
+  end;
+
+  LOperationsHashTree := TOperationsHashTree.Create;
+  try
+    LTotalSignerFee := 0;
+    LNoOfOperations := 0;
+    LOperationsTxt := '';
+    LOperationToString := '';
+
+    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
+    begin
+      LPCOperation := nil; // reset LPCOperation to Nil
+      LCurrentAccount := ASelectedAccounts[LAccountIdx];
+
+      if TAccountComp.IsAccountForSale(LCurrentAccount.accountInfo) then
+      begin
+        AErrorMessage := Format('Account "%s" Is Already Enlisted For Sale', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+
+      if (ASellerAccount.account = LCurrentAccount.account) then
+      begin
+        AErrorMessage := 'Seller Account Cannot Be Same As Account To Be Sold.';
+        Exit(False);
+      end;
+
+      if (LNode.Node.Bank.SafeBox.CurrentProtocol = CT_PROTOCOL_1) then
+      begin
+        AErrorMessage := 'This Operation Needs PROTOCOL 2 Active';
+        Exit(False);
+      end;
+
+      if AAccountSaleMode = akaPrivateSale then
+      begin
+
+        if TAccountComp.EqualAccountKeys(APublicKey,
+          LCurrentAccount.accountInfo.accountKey) then
+        begin
+          AErrorMessage := 'You Cannot Sell To An Account That You Want To Enlist For Sale.';
+          Exit(False);
+        end;
+
+        if ALockedUntilBlock = 0 then
+        begin
+          AErrorMessage := 'You Didn''t Insert a Locking Block.';
+          Exit(False);
+        end;
+      end;
+
+      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, APublicKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
+      begin
+        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
+        Exit(False);
+      end;
+
+      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
+      if LIdx < 0 then
+      begin
+        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+      LWalletKey := LWalletKeys.Key[LIdx];
+
+      if not Assigned(LWalletKey.PrivateKey) then
+      begin
+        if LWalletKey.HasPrivateKey then
+          AErrorMessage := 'Wallet Is Password Protected. Please Unlock Before You Proceed.'
+        else
+          AErrorMessage := Format('Only Public Key Of Account %s Was Found In Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
+        Exit(False);
+      end;
+
+      if ASignerAccount.balance > AFee then
+        LFee := AFee
+      else
+        LFee := ASignerAccount.balance;
+
+      case AAccountSaleMode of
+        akaPublicSale:
+
+          LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
+            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
+            LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
+            APublicKey, 0, LWalletKey.PrivateKey, LPayloadEncodedBytes);
+
+        akaPrivateSale:
+
+          LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
+            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
+            LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
+            APublicKey, ALockedUntilBlock, LWalletKey.PrivateKey, LPayloadEncodedBytes)
+        else
+          raise Exception.Create('Invalid Account Sale Type')
+      end;
+
+      try
+        LOperationsTxt := Format('Enlist Account For Sale At a Price Of "%s" PASC', [TAccountComp.FormatMoney(ASalePrice)]);
+        if Assigned(LPCOperation) then
+        begin
+          LOperationsHashTree.AddOperationToHashTree(LPCOperation);
+          Inc(LNoOfOperations);
+          Inc(LTotalSignerFee, LFee);
+          if LOperationToString <> '' then
+            LOperationToString := LOperationToString + #10;
+          LOperationToString := LOperationToString + LPCOperation.ToString;
+        end;
+      finally
+        FreeAndNil(LPCOperation);
+      end;
+
+    end;
+
+    if (LOperationsHashTree.OperationsCount = 0) then
+    begin
+      AErrorMessage := 'No Valid Operation to Execute';
+      Exit(False);
+    end;
+
+    Exit(TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
+
+  finally
+    LOperationsHashTree.Free;
+  end;
+end;
+
 end.

+ 1 - 1
src/gui-experimental/wizards/operations/UWIZChangeKey.pas

@@ -33,7 +33,7 @@ type
 implementation
 
 uses
-  UWallet,
+  UWallet, UCoreUtils,
   UWIZOperationSelected,
   UWIZChangeKey_SelectOption,
   UWIZOperationConfirmation;

+ 1 - 1
src/gui-experimental/wizards/operations/UWIZEnlistAccountForSale.pas

@@ -41,7 +41,7 @@ type
 implementation
 
 uses
-  UWallet,
+  UWallet, UCoreUtils,
   UWIZOperationSelected,
   UWIZEnlistAccountForSale_SelectOption,
   UWIZEnlistAccountForSale_EnterSeller,

+ 0 - 645
src/gui-experimental/wizards/operations/UWIZOperation.pas

@@ -140,21 +140,6 @@ type
       class property RelockOnFinish: Boolean read FRelockOnFinish write FRelockOnFinish;
   end;
 
-
-  { TWIZOperationsHelper }
-
-  TWIZOperationsHelper = class
-  private
-    class function UpdatePayload(const ASenderPublicKey, ADestinationPublicKey: TAccountKey; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent: string; var AEncodedPayloadBytes: TRawBytes; const APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
-    class function SendPASCFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalAmount, ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean; static;
-    class function OthersFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean; static;
-  public
-    class function ExecuteOperations(const ANewOps: TWIZOperationsModel; AHandler: TWIZOperationsModel.TOperationExecuteResultHandler; var errors: ansistring): boolean; static;
-    class function ExecuteSendPASC(const ASelectedAccounts: TArray<TAccount>; const ADestinationAccount, ASignerAccount: TAccount; AAmount, AFee: int64; const ASendPASCMode: TSendPASCMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
-    class function ExecuteChangeKey(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount: TAccount; APublicKey: TAccountKey; AFee: int64; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
-    class function ExecuteEnlistAccountForSale(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount, ASellerAccount: TAccount; const APublicKey: TAccountKey; AFee, ASalePrice: int64; ALockedUntilBlock: UInt32; const AAccountSaleMode: TAccountSaleMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean; static;
-  end;
-
 implementation
 
 uses
@@ -178,634 +163,4 @@ begin
   FPayload := TPayloadModel.Create(Self);
 end;
 
-{ TWIZOperationsHelper }
-
-class function TWIZOperationsHelper.SendPASCFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalAmount, ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean;
-var
-  LAuxs, LOperationsTxt: string;
-  i: integer;
-begin
-  LOperationsTxt := AOperationsTxt;
-  if (ANoOfOperations > 1) then
-  begin
-    LAuxs := 'Total amount that dest will receive: ' + TAccountComp.FormatMoney(
-      ATotalAmount) + #10;
-    if Application.MessageBox(
-      PChar('Execute ' + IntToStr(ANoOfOperations) +
-      ' operations?' + #10 + 'Operation: ' + LOperationsTxt + #10 +
-      LAuxs + 'Total fee: ' + TAccountComp.FormatMoney(ATotalFee) +
-      #10 + #10 + 'Note: This operation will be transmitted to the network!'),
-      PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
-      idYes then
-      Exit;
-  end
-  else
-  if Application.MessageBox(PChar('Execute this operation:' +
-    #10 + #10 + AOperationToString + #10 + #10 +
-    'Note: This operation will be transmitted to the network!'),
-    PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
-    idYes then
-    Exit;
-  Result := True;
-  i := TNode.Node.AddOperations(nil, AOperationsHashTree, nil, AErrorMessage);
-  if (i = AOperationsHashTree.OperationsCount) then
-  begin
-    LOperationsTxt := 'Successfully executed ' + IntToStr(i) +
-      ' operations!' + #10 + #10 + AOperationToString;
-    if i > 1 then
-      ShowMessage(LOperationsTxt)
-    else
-    begin
-      Application.MessageBox(
-        PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
-        #10 + #10 + AOperationToString),
-        PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
-    end;
-  end
-  else if (i > 0) then
-  begin
-    LOperationsTxt := 'One or more of your operations has not been executed:' +
-      #10 + 'Errors:' + #10 + AErrorMessage + #10 + #10 +
-      'Total successfully executed operations: ' + IntToStr(i);
-    ShowMessage(LOperationsTxt);
-  end
-  else
-    Result := False;
-end;
-
-class function TWIZOperationsHelper.UpdatePayload(const ASenderPublicKey, ADestinationPublicKey: TAccountKey; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent: string; var AEncodedPayloadBytes: TRawBytes; const APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
-var
-  LValid: boolean;
-begin
-
-  if (APayloadContent = '') then
-    Exit(True);
-
-  LValid := False;
-  AErrorMessage := 'An Error Occured During Payload Encryption.';
-
-  try
-
-    case APayloadEncryptionMode of
-
-      pemEncryptWithSender:
-      begin
-        // Use sender public key
-        AEncodedPayloadBytes := ECIESEncrypt(ASenderPublicKey, APayloadContent);
-        LValid := AEncodedPayloadBytes <> '';
-      end;
-
-      pemEncryptWithReceiver:
-      begin
-        // With destination public key
-        AEncodedPayloadBytes := ECIESEncrypt(ADestinationPublicKey, APayloadContent);
-        LValid := AEncodedPayloadBytes <> '';
-      end;
-
-      pemEncryptWithPassword:
-      begin
-        // With defined password
-        if APayloadEncryptionPassword = '' then
-        begin
-          AErrorMessage := 'Payload Encryption Password Cannot Be Empty With The Chosen Option : "Encrypt With Password."';
-          Exit(False);
-        end;
-        AEncodedPayloadBytes := TAESComp.EVP_Encrypt_AES256(
-          APayloadContent, APayloadEncryptionPassword);
-        LValid := AEncodedPayloadBytes <> '';
-      end;
-
-      pemNotEncrypt:
-      begin
-        // no encryption
-        AEncodedPayloadBytes := APayloadContent;
-        LValid := True;
-      end
-
-      else
-      begin
-        AErrorMessage := 'Unknown Encryption Selected';
-        Exit(False);
-      end;
-    end;
-
-  finally
-    if LValid then
-      if Length(AEncodedPayloadBytes) > CT_MaxPayloadSize then
-      begin
-        LValid := False;
-        AErrorMessage := Format('Payload Size Is %d Which Is Bigger Than %d', [Length(AEncodedPayloadBytes), CT_MaxPayloadSize]);
-      end;
-    Result := LValid;
-  end;
-end;
-
-class function TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(const AOperationsTxt, AOperationToString: string; ANoOfOperations: integer; ATotalFee: int64; AOperationsHashTree: TOperationsHashTree; var AErrorMessage: string): boolean;
-var
-  LAuxs, LOperationsTxt: string;
-  i: integer;
-begin
-  LOperationsTxt := AOperationsTxt;
-  if (ANoOfOperations > 1) then
-  begin
-    LAuxs := '';
-    if Application.MessageBox(
-      PChar('Execute ' + IntToStr(ANoOfOperations) +
-      ' operations?' + #10 + 'Operation: ' + LOperationsTxt + #10 +
-      LAuxs + 'Total fee: ' + TAccountComp.FormatMoney(ATotalFee) +
-      #10 + #10 + 'Note: This operation will be transmitted to the network!'),
-      PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
-      idYes then
-      Exit;
-  end
-  else
-  if Application.MessageBox(PChar('Execute this operation:' +
-    #10 + #10 + AOperationToString + #10 + #10 +
-    'Note: This operation will be transmitted to the network!'),
-    PChar(Application.Title), MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2) <>
-    idYes then
-    Exit;
-  Result := True;
-  i := TNode.Node.AddOperations(nil, AOperationsHashTree, nil, AErrorMessage);
-  if (i = AOperationsHashTree.OperationsCount) then
-  begin
-    LOperationsTxt := 'Successfully executed ' + IntToStr(i) +
-      ' operations!' + #10 + #10 + AOperationToString;
-    if i > 1 then
-      ShowMessage(LOperationsTxt)
-    else
-    begin
-      Application.MessageBox(
-        PChar('Successfully executed ' + IntToStr(i) + ' operations!' +
-        #10 + #10 + AOperationToString),
-        PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
-    end;
-  end
-  else if (i > 0) then
-  begin
-    LOperationsTxt := 'One or more of your operations has not been executed:' +
-      #10 + 'Errors:' + #10 + AErrorMessage + #10 + #10 +
-      'Total successfully executed operations: ' + IntToStr(i);
-    ShowMessage(LOperationsTxt);
-  end
-  else
-    Result := False;
-end;
-
-class function TWIZOperationsHelper.ExecuteOperations(const ANewOps: TWIZOperationsModel; AHandler: TWIZOperationsModel.TOperationExecuteResultHandler; var errors: ansistring): boolean;
-begin
-
-end;
-
-class function TWIZOperationsHelper.ExecuteSendPASC(const ASelectedAccounts: TArray<TAccount>; const ADestinationAccount, ASignerAccount: TAccount; AAmount, AFee: int64; const ASendPASCMode: TSendPASCMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
-var
-  LWalletKey: TWalletKey;
-  LWalletKeys: TWalletKeys;
-  LNode: TNode;
-  LPCOperation: TPCOperation;
-  LOperationsHashTree: TOperationsHashTree;
-  LTotalAmount, LTotalSignerFee, LAmount, LFee: int64;
-  LDoOperation: boolean;
-  LOperationsTxt, LOperationToString: string;
-  LIdx, LAccountIdx, LNoOfOperations: integer;
-  LCurrentAccount: TAccount;
-  LPayloadEncodedBytes: TRawBytes;
-begin
-  if Length(ASelectedAccounts) = 0 then
-  begin
-    AErrorMessage := 'No Selected Account Found';
-    Exit(False);
-  end;
-
-  LWalletKeys := TWallet.Keys;
-  LNode := TNode.Node;
-
-  if not Assigned(LWalletKeys) then
-  begin
-    AErrorMessage := 'No Wallet Keys Found';
-    Exit(False);
-  end;
-
-  if not Assigned(LNode) then
-  begin
-    AErrorMessage := 'No Node Found';
-    Exit(False);
-  end;
-
-  LOperationsHashTree := TOperationsHashTree.Create;
-  try
-    LTotalAmount := 0;
-    LTotalSignerFee := 0;
-    LNoOfOperations := 0;
-    LOperationsTxt := '';
-    LOperationToString := '';
-    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
-    begin
-      LPCOperation := nil; // reset LPCOperation to Nil
-      LCurrentAccount := ASelectedAccounts[LAccountIdx];
-
-      if LCurrentAccount.account = ADestinationAccount.account then
-      begin
-        AErrorMessage := Format('Sender "%s" And Destination "%s" Accounts Are The Same', [LCurrentAccount.AccountString, ADestinationAccount.AccountString]);
-        Exit(False);
-      end;
-
-      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, ADestinationAccount.accountInfo.accountKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
-      begin
-        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
-        Exit(False);
-      end;
-
-      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
-      if LIdx < 0 then
-      begin
-        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-      LWalletKey := LWalletKeys.Key[LIdx];
-
-      if not Assigned(LWalletKey.PrivateKey) then
-      begin
-        if LWalletKey.HasPrivateKey then
-          AErrorMessage := 'Wallet is Password Protected. Please Unlock Before You Proceed.'
-        else
-          AErrorMessage := Format('Only Public Key of Account %s Was Found in Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-
-      LDoOperation := True;
-
-      if LCurrentAccount.balance > 0 then
-        case ASendPASCMode of
-          akaAllBalance:
-          begin
-            LAmount := LCurrentAccount.balance - AFee;
-            LFee := AFee;
-          end;
-
-          akaSpecifiedAmount:
-            if LCurrentAccount.balance >= UInt64(AAmount + AFee) then
-            begin
-              LAmount := AAmount;
-              LFee := AFee;
-            end
-            else
-            begin
-              AErrorMessage := Format('Insufficient Funds In "%s". %s < (%s + %s = %s)', [LCurrentAccount.AccountString, TAccountComp.FormatMoney(LCurrentAccount.balance), TAccountComp.FormatMoney(AAmount), TAccountComp.FormatMoney(AFee), TAccountComp.FormatMoney(AAmount + AFee)]);
-              Exit(False);
-            end;
-        end
-      else
-        LDoOperation := False;
-
-      if LDoOperation then
-      begin
-        LPCOperation := TOpTransaction.CreateTransaction(
-           TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation + 1, ADestinationAccount.account, LWalletKey.PrivateKey, LAmount, LFee, LPayloadEncodedBytes);
-        try
-          LOperationsTxt := Format('Transaction To "%s"', [ADestinationAccount.AccountString]);
-
-          if Assigned(LPCOperation) then
-          begin
-            LOperationsHashTree.AddOperationToHashTree(LPCOperation);
-            Inc(LTotalAmount, LAmount);
-            Inc(LTotalSignerFee, LFee);
-            Inc(LNoOfOperations);
-            if LOperationToString <> '' then
-              LOperationToString := LOperationToString + #10;
-            LOperationToString := LOperationToString + LPCOperation.ToString;
-          end;
-        finally
-          FreeAndNil(LPCOperation);
-        end;
-      end;
-
-    end;
-    if (LOperationsHashTree.OperationsCount = 0) then
-    begin
-      AErrorMessage := 'No Valid Operation To Execute';
-      Exit(False);
-    end;
-
-    Exit(TWIZOperationsHelper.SendPASCFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalAmount, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
-  finally
-    LOperationsHashTree.Free;
-  end;
-
-end;
-
-class function TWIZOperationsHelper.ExecuteChangeKey(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount: TAccount; APublicKey: TAccountKey; AFee: int64; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
-var
-  LWalletKey: TWalletKey;
-  LWalletKeys: TWalletKeys;
-  LNode: TNode;
-  LPCOperation: TPCOperation;
-  LOperationsHashTree: TOperationsHashTree;
-  LTotalSignerFee, LFee: int64;
-  LIsV2: boolean;
-  LOperationsTxt, LOperationToString: string;
-  LIdx, LAccountIdx, LNoOfOperations: integer;
-  LCurrentAccount, LSignerAccount: TAccount;
-  LPayloadEncodedBytes: TRawBytes;
-label
-  loop_start;
-begin
-  if Length(ASelectedAccounts) = 0 then
-  begin
-    AErrorMessage := 'No Selected Account Found';
-    Exit(False);
-  end;
-
-  LWalletKeys := TWallet.Keys;
-  LNode := TNode.Node;
-
-  if not Assigned(LWalletKeys) then
-  begin
-    AErrorMessage := 'No Wallet Keys Found';
-    Exit(False);
-  end;
-
-  if not Assigned(LNode) then
-  begin
-    AErrorMessage := 'No Node Found';
-    Exit(False);
-  end;
-
-  LOperationsHashTree := TOperationsHashTree.Create;
-  try
-    LIsV2 := LNode.Bank.SafeBox.CurrentProtocol >= CT_PROTOCOL_2;
-    LTotalSignerFee := 0;
-    LNoOfOperations := 0;
-    LOperationsTxt := '';
-    LOperationToString := '';
-    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
-    begin
-      loop_start:
-        LPCOperation := nil; // reset LPCOperation to Nil
-      LCurrentAccount := ASelectedAccounts[LAccountIdx];
-
-      if (TAccountComp.EqualAccountKeys(LCurrentAccount.accountInfo.accountKey,
-        APublicKey)) then
-      begin
-        AErrorMessage := 'New Key Is Same As Current Key';
-        Exit(False);
-      end;
-
-      if LNode.Bank.SafeBox.CurrentProtocol >= 1 then
-      begin
-        // Signer:
-        LSignerAccount := ASignerAccount;
-        if (TAccountComp.IsAccountLocked(LSignerAccount.accountInfo,
-          LNode.Bank.BlocksCount)) then
-        begin
-          AErrorMessage := Format('Signer Account "%s"  Is Locked Until Block %u', [LSignerAccount.AccountString, LSignerAccount.accountInfo.locked_until_block]);
-          Exit(False);
-        end;
-        if (not TAccountComp.EqualAccountKeys(
-          LSignerAccount.accountInfo.accountKey, LCurrentAccount.accountInfo.accountKey)) then
-        begin
-          AErrorMessage := Format('Signer Account %s Is Not The Owner Of Account %s', [LSignerAccount.AccountString, LCurrentAccount.AccountString]);
-          Exit(False);
-        end;
-      end
-      else
-        LSignerAccount := LCurrentAccount;
-
-      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, APublicKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
-      begin
-        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
-        Exit(False);
-      end;
-
-      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
-      if LIdx < 0 then
-      begin
-        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-      LWalletKey := LWalletKeys.Key[LIdx];
-
-      if not Assigned(LWalletKey.PrivateKey) then
-      begin
-        if LWalletKey.HasPrivateKey then
-          AErrorMessage := 'Wallet Is Password Protected. Please Unlock Before You Proceed.'
-        else
-          AErrorMessage := Format('Only Public Key of Account %s Was Found In Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-
-      if LIsV2 then
-      begin
-        // must ensure is Signer account last if included in sender accounts (not necessarily ordered enumeration)
-        if (LAccountIdx < Length(ASelectedAccounts) - 1) and
-          (LCurrentAccount.account = LSignerAccount.account) then
-        begin
-          TArrayTool<TAccount>.Swap(ASelectedAccounts, LAccountIdx,
-            Length(ASelectedAccounts) - 1); // ensure signer account processed last
-          goto loop_start; // TODO: remove ugly hack with refactoring!
-        end;
-
-        // Maintain correct signer fee distribution
-        if Uint64(LTotalSignerFee) >= LSignerAccount.balance then
-          LFee := 0
-        else if LSignerAccount.balance - uint64(LTotalSignerFee) >
-          UInt64(AFee) then
-          LFee := AFee
-        else
-          LFee := LSignerAccount.balance - UInt64(LTotalSignerFee);
-        LPCOperation := TOpChangeKeySigned.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LSignerAccount.account,
-          LSignerAccount.n_operation + LNoOfOperations + 1, LCurrentAccount.account,
-          LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
-      end
-      else
-        LPCOperation := TOpChangeKey.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation +
-          1, LCurrentAccount.account, LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
-
-      try
-        LOperationsTxt := Format('Change Key To "%s"', [TAccountComp.GetECInfoTxt(APublicKey.EC_OpenSSL_NID)]);
-        if Assigned(LPCOperation) then
-        begin
-          LOperationsHashTree.AddOperationToHashTree(LPCOperation);
-          Inc(LNoOfOperations);
-          Inc(LTotalSignerFee, LFee);
-          if LOperationToString <> '' then
-            LOperationToString := LOperationToString + #10;
-          LOperationToString := LOperationToString + LPCOperation.ToString;
-        end;
-      finally
-        FreeAndNil(LPCOperation);
-      end;
-
-    end;
-
-    if (LOperationsHashTree.OperationsCount = 0) then
-    begin
-      AErrorMessage := 'No Valid Operation to Execute';
-      Exit(False);
-    end;
-
-    Exit(TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
-  finally
-    LOperationsHashTree.Free;
-  end;
-
-end;
-
-class function TWIZOperationsHelper.ExecuteEnlistAccountForSale(const ASelectedAccounts: TArray<TAccount>; const ASignerAccount, ASellerAccount: TAccount; const APublicKey: TAccountKey; AFee, ASalePrice: int64; ALockedUntilBlock: UInt32; const AAccountSaleMode: TAccountSaleMode; const APayloadEncryptionMode: TPayloadEncryptionMode; const APayloadContent, APayloadEncryptionPassword: string; var AErrorMessage: string): boolean;
-var
-  LWalletKey: TWalletKey;
-  LWalletKeys: TWalletKeys;
-  LNode: TNode;
-  LPCOperation: TPCOperation;
-  LOperationsHashTree: TOperationsHashTree;
-  LTotalSignerFee, LFee: int64;
-  LOperationsTxt, LOperationToString: string;
-  LIdx, LAccountIdx, LNoOfOperations: integer;
-  LCurrentAccount, LSignerAccount: TAccount;
-  LPayloadEncodedBytes: TRawBytes;
-begin
-  if Length(ASelectedAccounts) = 0 then
-  begin
-    AErrorMessage := 'No Selected Account Found';
-    Exit(False);
-  end;
-
-  LWalletKeys := TWallet.Keys;
-  LNode := TNode.Node;
-
-  if not Assigned(LWalletKeys) then
-  begin
-    AErrorMessage := 'No Wallet Keys Found';
-    Exit(False);
-  end;
-
-  if not Assigned(LNode) then
-  begin
-    AErrorMessage := 'No Node Found';
-    Exit(False);
-  end;
-
-  LOperationsHashTree := TOperationsHashTree.Create;
-  try
-    LTotalSignerFee := 0;
-    LNoOfOperations := 0;
-    LOperationsTxt := '';
-    LOperationToString := '';
-
-    for LAccountIdx := Low(ASelectedAccounts) to High(ASelectedAccounts) do
-    begin
-      LPCOperation := nil; // reset LPCOperation to Nil
-      LCurrentAccount := ASelectedAccounts[LAccountIdx];
-
-      if TAccountComp.IsAccountForSale(LCurrentAccount.accountInfo) then
-      begin
-        AErrorMessage := Format('Account "%s" Is Already Enlisted For Sale', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-
-      if (ASellerAccount.account = LCurrentAccount.account) then
-      begin
-        AErrorMessage := 'Seller Account Cannot Be Same As Account To Be Sold.';
-        Exit(False);
-      end;
-
-      if (LNode.Node.Bank.SafeBox.CurrentProtocol = CT_PROTOCOL_1) then
-      begin
-        AErrorMessage := 'This Operation Needs PROTOCOL 2 Active';
-        Exit(False);
-      end;
-
-      if AAccountSaleMode = akaPrivateSale then
-      begin
-
-        if TAccountComp.EqualAccountKeys(APublicKey,
-          LCurrentAccount.accountInfo.accountKey) then
-        begin
-          AErrorMessage := 'You Cannot Sell To An Account That You Want To Enlist For Sale.';
-          Exit(False);
-        end;
-
-        if ALockedUntilBlock = 0 then
-        begin
-          AErrorMessage := 'You Didn''t Insert a Locking Block.';
-          Exit(False);
-        end;
-      end;
-
-      if not UpdatePayload(LCurrentAccount.accountInfo.accountKey, APublicKey, APayloadEncryptionMode, APayloadContent, LPayloadEncodedBytes, APayloadEncryptionPassword, AErrorMessage) then
-      begin
-        AErrorMessage := Format('Error Encoding Payload Of Selected Account "%s. ", Specific Error Is "%s"', [LCurrentAccount.AccountString, AErrorMessage]);
-        Exit(False);
-      end;
-
-      LIdx := LWalletKeys.IndexOfAccountKey(LCurrentAccount.accountInfo.accountKey);
-      if LIdx < 0 then
-      begin
-        AErrorMessage := Format('Selected Account "%s" Private Key Not Found In Wallet', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-      LWalletKey := LWalletKeys.Key[LIdx];
-
-      if not Assigned(LWalletKey.PrivateKey) then
-      begin
-        if LWalletKey.HasPrivateKey then
-          AErrorMessage := 'Wallet Is Password Protected. Please Unlock Before You Proceed.'
-        else
-          AErrorMessage := Format('Only Public Key Of Account %s Was Found In Wallet. You Cannot Operate This Account', [LCurrentAccount.AccountString]);
-        Exit(False);
-      end;
-
-      if ASignerAccount.balance > AFee then
-        LFee := AFee
-      else
-        LFee := ASignerAccount.balance;
-
-      case AAccountSaleMode of
-        akaPublicSale:
-
-          LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
-            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
-            LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
-            APublicKey, 0, LWalletKey.PrivateKey, LPayloadEncodedBytes);
-
-        akaPrivateSale:
-
-          LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
-            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
-            LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
-            APublicKey, ALockedUntilBlock, LWalletKey.PrivateKey, LPayloadEncodedBytes)
-        else
-          raise Exception.Create('Invalid Account Sale Type')
-      end;
-
-      try
-        LOperationsTxt := Format('Enlist Account For Sale At a Price Of "%s" PASC', [TAccountComp.FormatMoney(ASalePrice)]);
-        if Assigned(LPCOperation) then
-        begin
-          LOperationsHashTree.AddOperationToHashTree(LPCOperation);
-          Inc(LNoOfOperations);
-          Inc(LTotalSignerFee, LFee);
-          if LOperationToString <> '' then
-            LOperationToString := LOperationToString + #10;
-          LOperationToString := LOperationToString + LPCOperation.ToString;
-        end;
-      finally
-        FreeAndNil(LPCOperation);
-      end;
-
-    end;
-
-    if (LOperationsHashTree.OperationsCount = 0) then
-    begin
-      AErrorMessage := 'No Valid Operation to Execute';
-      Exit(False);
-    end;
-
-    Exit(TWIZOperationsHelper.OthersFinalizeAndDisplayMessage(LOperationsTxt, LOperationToString, LNoOfOperations, LTotalSignerFee, LOperationsHashTree, AErrorMessage));
-
-  finally
-    LOperationsHashTree.Free;
-  end;
-end;
-
 end.

+ 2 - 1
src/gui-experimental/wizards/operations/UWIZSendPASC.pas

@@ -43,7 +43,8 @@ uses
   UWallet,
   UWIZOperationSelected,
   UWIZSendPASC_Details,
-  UWIZOperationConfirmation;
+  UWIZOperationConfirmation,
+  UCoreUtils;
 
 { TWIZSendPASCWizard }