UFRMOperation.pas 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. unit UFRMOperation;
  2. { Copyright (c) 2016 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. THIS LICENSE HEADER MUST NOT BE REMOVED.
  12. }
  13. {$mode delphi}
  14. interface
  15. {$I ..\config.inc}
  16. uses
  17. LCLIntf, LCLType, LMessages,
  18. Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  19. Dialogs, StdCtrls, UCommon.UI,
  20. UNode, UWallet, UCrypto, Buttons, UBlockChain, UBaseTypes,
  21. UAccounts, UFRMAccountSelect, ActnList, ComCtrls, Types, UCommon, UPCOrderedLists;
  22. Const
  23. CM_PC_WalletKeysChanged = WM_USER + 1;
  24. type
  25. { TFRMOperation }
  26. TFRMOperation = class(TApplicationForm)
  27. ebChangeName: TEdit;
  28. ebChangeType: TEdit;
  29. ebSignerAccount: TEdit;
  30. lblSignerAccount: TLabel;
  31. lblAccountCaption: TLabel;
  32. bbExecute: TBitBtn;
  33. bbCancel: TBitBtn;
  34. lblAccountBalance: TLabel;
  35. lblChangeType: TLabel;
  36. lblChangeName: TLabel;
  37. lblBalanceCaption: TLabel;
  38. ebSenderAccount: TEdit;
  39. lblChangeInfoErrors: TLabel;
  40. PageControlLocked: TPageControl;
  41. sbSearchBuyAccount: TSpeedButton;
  42. sbSearchListerSellerAccount: TSpeedButton;
  43. sbSearchDestinationAccount: TSpeedButton;
  44. sbSearchSignerAccount: TSpeedButton;
  45. tsChangeInfo: TTabSheet;
  46. tsOperation: TTabSheet;
  47. gbPayload: TGroupBox;
  48. lblEncryptPassword: TLabel;
  49. Label4: TLabel;
  50. lblEncryptionErrors: TLabel;
  51. lblPayloadLength: TLabel;
  52. rbEncryptedWithEC: TRadioButton;
  53. rbEncrptedWithPassword: TRadioButton;
  54. rbNotEncrypted: TRadioButton;
  55. ebEncryptPassword: TEdit;
  56. memoPayload: TMemo;
  57. rbEncryptedWithOldEC: TRadioButton;
  58. ActionList: TActionList;
  59. actExecute: TAction;
  60. tsGlobalError: TTabSheet;
  61. lblGlobalErrors: TLabel;
  62. bbPassword: TBitBtn;
  63. memoAccounts: TMemo;
  64. lblAccountsCount: TLabel;
  65. lblFee: TLabel;
  66. ebFee: TEdit;
  67. PageControlOpType: TPageControl;
  68. tsTransaction: TTabSheet;
  69. lblDestAccount: TLabel;
  70. lblAmount: TLabel;
  71. lblTransactionErrors: TLabel;
  72. ebDestAccount: TEdit;
  73. ebAmount: TEdit;
  74. tsChangePrivateKey: TTabSheet;
  75. gbChangeKey: TGroupBox;
  76. lblNewPrivateKey: TLabel;
  77. lblNewOwnerPublicKey: TLabel;
  78. lblNewOwnerErrors: TLabel;
  79. lblChangeKeyErrors: TLabel;
  80. rbChangeKeyWithAnother: TRadioButton;
  81. cbNewPrivateKey: TComboBox;
  82. ebNewPublicKey: TEdit;
  83. bbChangePrivateKeyKeys: TBitBtn;
  84. rbChangeKeyTransferAccountToNewOwner: TRadioButton;
  85. tsListForSale: TTabSheet;
  86. gbSaleType: TGroupBox;
  87. Label1: TLabel;
  88. Label3: TLabel;
  89. lblSaleNewOwnerPublicKey: TLabel;
  90. lblSaleLockedUntilBlock: TLabel;
  91. rbListAccountForPublicSale: TRadioButton;
  92. rbListAccountForPrivateSale: TRadioButton;
  93. ebSalePrice: TEdit;
  94. ebSellerAccount: TEdit;
  95. ebSaleNewOwnerPublicKey: TEdit;
  96. ebSaleLockedUntilBlock: TEdit;
  97. tsDelist: TTabSheet;
  98. tsBuyAccount: TTabSheet;
  99. lblListAccountErrors: TLabel;
  100. lblAccountToBuy: TLabel;
  101. ebAccountToBuy: TEdit;
  102. lblBuyAmount: TLabel;
  103. ebBuyAmount: TEdit;
  104. lblBuyAccountErrors: TLabel;
  105. lblBuyNewKey: TLabel;
  106. cbBuyNewKey: TComboBox;
  107. bbBuyNewKey: TBitBtn;
  108. Label2: TLabel;
  109. lblDelistErrors: TLabel;
  110. procedure ebNewPublicKeyExit(Sender: TObject);
  111. procedure FormCreate(Sender: TObject);
  112. procedure FormDestroy(Sender: TObject);
  113. procedure memoPayloadClick(Sender: TObject);
  114. procedure ebEncryptPasswordChange(Sender: TObject);
  115. procedure bbChangePrivateKeyKeysClick(Sender: TObject);
  116. procedure actExecuteExecute(Sender: TObject);
  117. procedure ebSenderAccountExit(Sender: TObject);
  118. procedure ebSenderAccountKeyPress(Sender: TObject; var Key: Char);
  119. procedure bbPasswordClick(Sender: TObject);
  120. procedure PageControlOpTypeChange(Sender: TObject);
  121. procedure sbSearchBuyAccountClick(Sender: TObject);
  122. procedure sbSearchDestinationAccountClick(Sender: TObject);
  123. procedure sbSearchListerSellerAccountClick(Sender: TObject);
  124. procedure sbSearchSignerAccountClick(Sender: TObject);
  125. procedure updateInfoClick(Sender: TObject);
  126. procedure bbBuyNewKeyClick(Sender: TObject);
  127. procedure ebAccountNumberExit(Sender: TObject);
  128. procedure ebCurrencyExit(Sender: TObject);
  129. private
  130. FNode : TNode;
  131. FWalletKeys: TWalletKeys;
  132. FDefaultFee: Int64;
  133. FEncodedPayload : TRawBytes;
  134. FDisabled : Boolean;
  135. FSenderAccounts: TOrderedCardinalList; // TODO: TOrderedCardinalList should be replaced with a "TCardinalList" since signer account should be processed last
  136. procedure SetWalletKeys(const Value: TWalletKeys);
  137. Procedure UpdateWalletKeys;
  138. { Private declarations }
  139. Procedure UpdateAccountsInfo;
  140. Function UpdateFee(var Fee : Int64; errors : AnsiString) : Boolean;
  141. Function UpdateOperationOptions(var errors : AnsiString) : Boolean;
  142. Function UpdatePayload(Const SenderAccount : TAccount; var errors : AnsiString) : Boolean;
  143. Function UpdateOpTransaction(Const SenderAccount : TAccount; var DestAccount : TAccount; var amount : Int64; var errors : AnsiString) : Boolean;
  144. Function UpdateOpChangeKey(Const TargetAccount : TAccount; var SignerAccount : TAccount; var NewPublicKey : TAccountKey; var errors : AnsiString) : Boolean;
  145. Function UpdateOpListForSale(Const TargetAccount : TAccount; var SalePrice : Int64; var SellerAccount,SignerAccount : TAccount; var NewOwnerPublicKey : TAccountKey; var LockedUntilBlock : Cardinal; var errors : AnsiString) : Boolean;
  146. Function UpdateOpDelist(Const TargetAccount : TAccount; var SignerAccount : TAccount; var errors : AnsiString) : Boolean;
  147. Function UpdateOpBuyAccount(Const SenderAccount : TAccount; var AccountToBuy : TAccount; var amount : Int64; var NewPublicKey : TAccountKey; var errors : AnsiString) : Boolean;
  148. Function UpdateOpChangeInfo(Const TargetAccount : TAccount; var SignerAccount : TAccount; var changeName : Boolean; var newName : AnsiString; var changeType : Boolean; var newType : Word; var errors : AnsiString) : Boolean;
  149. procedure SetDefaultFee(const Value: Int64);
  150. Procedure OnSenderAccountsChanged(Sender : TObject);
  151. procedure OnWalletKeysChanged(Sender : TObject);
  152. procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
  153. Function GetDefaultSenderAccount : TAccount;
  154. procedure ebAccountKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  155. protected
  156. procedure searchAccount(editBox : TCustomEdit);
  157. public
  158. { Public declarations }
  159. Property SenderAccounts : TOrderedCardinalList read FSenderAccounts;
  160. Property WalletKeys : TWalletKeys read FWalletKeys write SetWalletKeys;
  161. Property DefaultFee : Int64 read FDefaultFee write SetDefaultFee;
  162. end;
  163. implementation
  164. uses
  165. UECIES, UConst, UOpTransaction, UAES, UFRMWalletKeys, UUserInterface, UPCDataTypes;
  166. {$R *.lfm}
  167. { TFRMOperation }
  168. procedure TFRMOperation.actExecuteExecute(Sender: TObject);
  169. Var errors : AnsiString;
  170. P : PAccount;
  171. i,iAcc : Integer;
  172. wk : TWalletKey;
  173. ops : TOperationsHashTree;
  174. op : TPCOperation;
  175. account,signerAccount,destAccount,accountToBuy : TAccount;
  176. operation_to_string, operationstxt, auxs : String;
  177. _amount,_fee, _totalamount, _totalfee, _totalSignerFee, _salePrice : Int64;
  178. _lockedUntil, _signer_n_ops : Cardinal;
  179. dooperation : Boolean;
  180. _newOwnerPublicKey : TECDSA_Public;
  181. _newName : TRawBytes;
  182. _newType : Word;
  183. _changeName, _changeType, _V2, _executeSigner : Boolean;
  184. _senderAccounts : TCardinalsArray;
  185. label loop_start;
  186. begin
  187. if Not Assigned(WalletKeys) then raise Exception.Create('No wallet keys');
  188. If Not UpdateOperationOptions(errors) then raise Exception.Create(errors);
  189. ops := TOperationsHashTree.Create;
  190. Try
  191. _V2 := FNode.Bank.SafeBox.CurrentProtocol >= CT_PROTOCOL_2;
  192. _totalamount := 0;
  193. _totalfee := 0;
  194. _totalSignerFee := 0;
  195. _signer_n_ops := 0;
  196. operationstxt := '';
  197. operation_to_string := '';
  198. // Compile FSenderAccounts into a reorderable array
  199. _senderAccounts := FSenderAccounts.ToArray;
  200. // Loop through each sender account
  201. for iAcc := 0 to Length(_senderAccounts) - 1 do begin
  202. loop_start:
  203. op := Nil;
  204. account := FNode.Operations.SafeBoxTransaction.Account(_senderAccounts[iAcc]);
  205. If Not UpdatePayload(account, errors) then
  206. raise Exception.Create('Error encoding payload of sender account '+TAccountComp.AccountNumberToAccountTxtNumber(account.account)+': '+errors);
  207. i := WalletKeys.IndexOfAccountKey(account.accountInfo.accountKey);
  208. if i<0 then begin
  209. Raise Exception.Create('Sender account private key not found in Wallet');
  210. end;
  211. wk := WalletKeys.Key[i];
  212. dooperation := true;
  213. // Default fee
  214. if account.balance > uint64(DefaultFee) then _fee := DefaultFee else _fee := account.balance;
  215. // Determine which operation type it is
  216. if PageControlOpType.ActivePage = tsTransaction then begin
  217. {%region Operation: Transaction}
  218. if Not UpdateOpTransaction(account,destAccount,_amount,errors) then raise Exception.Create(errors);
  219. if Length(_senderAccounts) > 1 then begin
  220. if account.balance>0 then begin
  221. if account.balance>DefaultFee then begin
  222. _amount := account.balance - DefaultFee;
  223. _fee := DefaultFee;
  224. end else begin
  225. _amount := account.balance;
  226. _fee := 0;
  227. end;
  228. end else dooperation := false;
  229. end else begin
  230. end;
  231. if dooperation then begin
  232. op := TOpTransaction.CreateTransaction(FNode.Bank.SafeBox.CurrentProtocol,
  233. account.account,account.n_operation+1,destAccount.account,wk.PrivateKey,_amount,_fee,FEncodedPayload);
  234. inc(_totalamount,_amount);
  235. inc(_totalfee,_fee);
  236. end;
  237. operationstxt := 'Transaction to '+TAccountComp.AccountNumberToAccountTxtNumber(destAccount.account);
  238. {%endregion}
  239. end else if (PageControlOpType.ActivePage = tsChangePrivateKey) then begin
  240. {%region Operation: Change Private Key}
  241. if Not UpdateOpChangeKey(account,signerAccount,_newOwnerPublicKey,errors) then raise Exception.Create(errors);
  242. if _V2 then begin
  243. // must ensure is Signer account last if included in sender accounts (not necessarily ordered enumeration)
  244. if (iAcc < Length(_senderAccounts) - 1) AND (account.account = signerAccount.account) then begin
  245. TArrayTool<Cardinal>.Swap(_senderAccounts, iAcc, Length(_senderAccounts) - 1); // ensure signer account processed last
  246. goto loop_start; // TODO: remove ugly hack with refactoring!
  247. end;
  248. // Maintain correct signer fee distribution
  249. if uint64(_totalSignerFee) >= signerAccount.balance then _fee := 0
  250. else if signerAccount.balance - uint64(_totalSignerFee) > uint64(DefaultFee) then _fee := DefaultFee
  251. else _fee := signerAccount.balance - uint64(_totalSignerFee);
  252. op := TOpChangeKeySigned.Create(FNode.Bank.SafeBox.CurrentProtocol,signerAccount.account,signerAccount.n_operation+_signer_n_ops+1,account.account,wk.PrivateKey,_newOwnerPublicKey,_fee,FEncodedPayload);
  253. inc(_signer_n_ops);
  254. inc(_totalSignerFee, _fee);
  255. end else begin
  256. op := TOpChangeKey.Create(FNode.Bank.SafeBox.CurrentProtocol,account.account,account.n_operation+1,account.account,wk.PrivateKey,_newOwnerPublicKey,_fee,FEncodedPayload);
  257. end;
  258. inc(_totalfee,_fee);
  259. operationstxt := 'Change private key to '+TAccountComp.GetECInfoTxt(_newOwnerPublicKey.EC_OpenSSL_NID);
  260. {%endregion}
  261. end else if (PageControlOpType.ActivePage = tsListForSale) then begin
  262. {%region Operation: List For Sale}
  263. If Not UpdateOpListForSale(account,_salePrice,destAccount,signerAccount,_newOwnerPublicKey,_lockedUntil,errors) then raise Exception.Create(errors);
  264. // Special fee account:
  265. if signerAccount.balance>DefaultFee then _fee := DefaultFee
  266. else _fee := signerAccount.balance;
  267. if (rbListAccountForPublicSale.Checked) then begin
  268. op := TOpListAccountForSale.CreateListAccountForSale(FNode.Bank.SafeBox.CurrentProtocol,signerAccount.account,signerAccount.n_operation+1+iAcc, account.account,_salePrice,_fee,destAccount.account,CT_TECDSA_Public_Nul,0,wk.PrivateKey,FEncodedPayload);
  269. end else if (rbListAccountForPrivateSale.Checked) then begin
  270. op := TOpListAccountForSale.CreateListAccountForSale(FNode.Bank.SafeBox.CurrentProtocol,signerAccount.account,signerAccount.n_operation+1+iAcc, account.account,_salePrice,_fee,destAccount.account,_newOwnerPublicKey,_lockedUntil,wk.PrivateKey,FEncodedPayload);
  271. end else raise Exception.Create('Select Sale type');
  272. {%endregion}
  273. end else if (PageControlOpType.ActivePage = tsDelist) then begin
  274. {%region Operation: Delist For Sale}
  275. if Not UpdateOpDelist(account,signerAccount,errors) then raise Exception.Create(errors);
  276. // Special fee account:
  277. if signerAccount.balance>DefaultFee then _fee := DefaultFee
  278. else _fee := signerAccount.balance;
  279. op := TOpDelistAccountForSale.CreateDelistAccountForSale(FNode.Bank.SafeBox.CurrentProtocol,signerAccount.account,signerAccount.n_operation+1+iAcc,account.account,_fee,wk.PrivateKey,FEncodedPayload);
  280. {%endregion}
  281. end else if (PageControlOpType.ActivePage = tsBuyAccount) then begin
  282. {%region Operation: Buy Account}
  283. if Not UpdateOpBuyAccount(account,accountToBuy,_amount,_newOwnerPublicKey,errors) then raise Exception.Create(errors);
  284. op := TOpBuyAccount.CreateBuy(FNode.Bank.SafeBox.CurrentProtocol,account.account,account.n_operation+1,accountToBuy.account,accountToBuy.accountInfo.account_to_pay,
  285. accountToBuy.accountInfo.price,_amount,_fee,_newOwnerPublicKey,wk.PrivateKey,FEncodedPayload);
  286. {%endregion}
  287. end else if (PageControlOpType.ActivePage = tsChangeInfo) then begin
  288. {%region Operation: Change Info}
  289. if not UpdateOpChangeInfo(account,signerAccount,_changeName,_newName,_changeType,_newType,errors) then raise Exception.Create(errors);
  290. if signerAccount.balance>DefaultFee then _fee := DefaultFee
  291. else _fee := signerAccount.balance;
  292. op := TOpChangeAccountInfo.CreateChangeAccountInfo(FNode.Bank.SafeBox.CurrentProtocol,signerAccount.account,signerAccount.n_operation+1,account.account,wk.PrivateKey,false,CT_TECDSA_Public_Nul,
  293. _changeName,_newName,_changeType,_newType,_fee,FEncodedPayload);
  294. {%endregion}
  295. end else begin
  296. raise Exception.Create('No operation selected');
  297. end;
  298. if Assigned(op) And (dooperation) then begin
  299. ops.AddOperationToHashTree(op);
  300. if operation_to_string<>'' then operation_to_string := operation_to_string + #10;
  301. operation_to_string := operation_to_string + op.ToString;
  302. end;
  303. FreeAndNil(op);
  304. end;
  305. if (ops.OperationsCount=0) then raise Exception.Create('No valid operation to execute');
  306. if (Length(_senderAccounts)>1) then begin
  307. if PageControlOpType.ActivePage = tsTransaction then auxs := 'Total amount that dest will receive: '+TAccountComp.FormatMoney(_totalamount)+#10
  308. else auxs:='';
  309. if Application.MessageBox(PChar('Execute '+Inttostr(Length(_senderAccounts))+' operations?'+#10+
  310. 'Operation: '+operationstxt+#10+
  311. auxs+
  312. 'Total fee: '+TAccountComp.FormatMoney(_totalfee)+#10+#10+'Note: This operation will be transmitted to the network!'),
  313. PChar(Application.Title),MB_YESNO+MB_ICONINFORMATION+MB_DEFBUTTON2)<>IdYes then exit;
  314. end else begin
  315. if Application.MessageBox(PChar('Execute this operation:'+#10+#10+operation_to_string+#10+#10+'Note: This operation will be transmitted to the network!'),
  316. PChar(Application.Title),MB_YESNO+MB_ICONINFORMATION+MB_DEFBUTTON2)<>IdYes then exit;
  317. end;
  318. i := FNode.AddOperations(nil,ops,Nil,errors);
  319. if (i=ops.OperationsCount) then begin
  320. Application.MessageBox(PChar('Successfully executed '+inttostr(i)+' operations!'+#10+#10+operation_to_string),PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
  321. ModalResult := MrOk;
  322. end else if (i>0) then begin
  323. Application.MessageBox(PChar('One or more of your operations has not been executed:'+#10+
  324. 'Errors:'+#10+
  325. errors+#10+#10+
  326. 'Total successfully executed operations: '+inttostr(i)),PChar(Application.Title),MB_OK+MB_ICONWARNING);
  327. ModalResult := MrOk;
  328. end else begin
  329. raise Exception.Create(errors);
  330. end;
  331. Finally
  332. ops.Free;
  333. End;
  334. end;
  335. procedure TFRMOperation.bbBuyNewKeyClick(Sender: TObject);
  336. Var FRM : TFRMWalletKeys;
  337. begin
  338. FRM := TFRMWalletKeys.Create(Self);
  339. Try
  340. FRM.ShowModal;
  341. cbBuyNewKey.SetFocus;
  342. UpdateWalletKeys;
  343. Finally
  344. FRM.Free;
  345. End;
  346. end;
  347. procedure TFRMOperation.bbChangePrivateKeyKeysClick(Sender: TObject);
  348. Var FRM : TFRMWalletKeys;
  349. begin
  350. FRM := TFRMWalletKeys.Create(Self);
  351. Try
  352. FRM.ShowModal;
  353. rbChangeKeyWithAnother.Checked := true;
  354. cbNewPrivateKey.SetFocus;
  355. UpdateWalletKeys;
  356. Finally
  357. FRM.Free;
  358. End;
  359. end;
  360. procedure TFRMOperation.bbPasswordClick(Sender: TObject);
  361. Var
  362. errors : AnsiString;
  363. begin
  364. if NOT FWalletKeys.IsValidPassword then begin
  365. TUserInterface.UnlockWallet(Self);
  366. SetWalletKeys(TWallet.Keys);
  367. UpdateOperationOptions(errors);
  368. end;
  369. end;
  370. procedure TFRMOperation.CM_WalletChanged(var Msg: TMessage);
  371. begin
  372. UpdateWalletKeys;
  373. end;
  374. procedure TFRMOperation.ebAccountNumberExit(Sender: TObject);
  375. Var an : Cardinal;
  376. eb : TEdit;
  377. begin
  378. if (Not assigned(Sender)) then exit;
  379. if (Not (Sender is TEdit)) then exit;
  380. eb := TEdit(Sender);
  381. If TAccountComp.AccountTxtNumberToAccountNumber(eb.Text,an) then begin
  382. eb.Text := TAccountComp.AccountNumberToAccountTxtNumber(an);
  383. end else begin
  384. eb.Text := '';
  385. end;
  386. updateInfoClick(Nil);
  387. end;
  388. procedure TFRMOperation.ebCurrencyExit(Sender: TObject);
  389. Var m : Int64;
  390. eb : TEdit;
  391. begin
  392. if (Not assigned(Sender)) then exit;
  393. if (Not (Sender is TEdit)) then exit;
  394. eb := TEdit(Sender);
  395. If Not (eb.ReadOnly) then begin
  396. if Not TAccountComp.TxtToMoney(eb.Text,m) then m:=0;
  397. eb.Text := TAccountComp.FormatMoney(m);
  398. updateInfoClick(Nil);
  399. end;
  400. end;
  401. procedure TFRMOperation.ebEncryptPasswordChange(Sender: TObject);
  402. begin
  403. if FDisabled then exit;
  404. rbEncrptedWithPassword.Checked := true;
  405. memoPayloadClick(Nil);
  406. end;
  407. procedure TFRMOperation.ebSenderAccountExit(Sender: TObject);
  408. Var an : Cardinal;
  409. begin
  410. If TAccountComp.AccountTxtNumberToAccountNumber(ebSenderAccount.Text,an) then begin
  411. SenderAccounts.Disable;
  412. try
  413. SenderAccounts.Clear;
  414. SenderAccounts.Add(an);
  415. finally
  416. SenderAccounts.Enable;
  417. end;
  418. ebSenderAccount.Text := TAccountComp.AccountNumberToAccountTxtNumber(an);
  419. end else begin
  420. if SenderAccounts.Count=1 then begin
  421. ebSenderAccount.Text := TAccountComp.AccountNumberToAccountTxtNumber(SenderAccounts.Get(0));
  422. end else begin
  423. ebSenderAccount.Text := '';
  424. end;
  425. end;
  426. end;
  427. procedure TFRMOperation.ebSenderAccountKeyPress(Sender: TObject; var Key: Char);
  428. begin
  429. if Key=#13 then ebSenderAccountExit(Nil);
  430. end;
  431. procedure TFRMOperation.FormCreate(Sender: TObject);
  432. begin
  433. FDisabled := false;
  434. FWalletKeys := Nil;
  435. FSenderAccounts := TOrderedCardinalList.Create;
  436. FSenderAccounts.OnListChanged := OnSenderAccountsChanged;
  437. FDisabled := true;
  438. FNode := TNode.Node;
  439. ebSenderAccount.OnKeyDown:=ebAccountKeyDown;
  440. ebSenderAccount.Tag:=CT_AS_MyAccounts;
  441. ebSignerAccount.Text:='';
  442. ebSignerAccount.OnChange := updateInfoClick;
  443. ebSignerAccount.OnExit := ebAccountNumberExit;
  444. ebSignerAccount.OnKeyDown := ebAccountKeyDown;
  445. ebSignerAccount.tag := CT_AS_MyAccounts;
  446. sbSearchSignerAccount.OnClick := sbSearchSignerAccountClick;
  447. //
  448. lblTransactionErrors.Caption := '';
  449. ebDestAccount.Text := '';
  450. ebDestAccount.OnChange := updateInfoClick;
  451. ebDestAccount.OnExit := ebAccountNumberExit;
  452. ebDestAccount.OnKeyDown := ebAccountKeyDown;
  453. ebAmount.Text := TAccountComp.FormatMoney(0);
  454. ebAmount.OnChange := updateInfoClick;
  455. ebAmount.OnExit := ebCurrencyExit;
  456. //
  457. lblChangeKeyErrors.Caption := '';
  458. lblNewOwnerErrors.Caption := '';
  459. rbChangeKeyWithAnother.OnClick := updateInfoClick;
  460. rbChangeKeyTransferAccountToNewOwner.OnClick := updateInfoClick;
  461. cbNewPrivateKey.OnChange := updateInfoClick;
  462. //
  463. lblListAccountErrors.Caption := '';
  464. rbListAccountForPublicSale.OnClick := updateInfoClick;
  465. rbListAccountForPrivateSale.OnClick := updateInfoClick;
  466. ebSalePrice.Text := TAccountComp.FormatMoney(0);
  467. ebSalePrice.OnChange := updateInfoClick;
  468. ebSalePrice.OnExit := ebCurrencyExit;
  469. ebSellerAccount.Text := '';
  470. ebSellerAccount.OnChange := updateInfoClick;
  471. ebSellerAccount.OnExit := ebAccountNumberExit;
  472. ebSellerAccount.OnKeyDown := ebAccountKeyDown;
  473. ebSellerAccount.tag := CT_AS_MyAccounts;
  474. ebSaleNewOwnerPublicKey.Text := '';
  475. ebSaleNewOwnerPublicKey.OnChange := updateInfoClick;
  476. ebSaleLockedUntilBlock.Text := '';
  477. ebSaleLockedUntilBlock.OnChange := updateInfoClick;
  478. //
  479. lblDelistErrors.Caption := '';
  480. //
  481. lblBuyAccountErrors.Caption := '';
  482. ebAccountToBuy.Text := '';
  483. ebAccountToBuy.OnChange := updateInfoClick;
  484. ebAccountToBuy.OnExit := ebAccountNumberExit;
  485. ebAccountToBuy.OnKeyDown := ebAccountKeyDown;
  486. ebAccountToBuy.tag := CT_AS_OnlyForSale;
  487. ebBuyAmount.Text := TAccountComp.FormatMoney(0);
  488. ebBuyAmount.OnChange := updateInfoClick;
  489. ebBuyAmount.OnExit := ebCurrencyExit;
  490. //
  491. ebChangeName.OnChange:=updateInfoClick;
  492. ebChangeType.OnChange:=updateInfoClick;
  493. //
  494. sbSearchDestinationAccount.OnClick := sbSearchDestinationAccountClick;
  495. sbSearchListerSellerAccount.OnClick := sbSearchListerSellerAccountClick;
  496. sbSearchBuyAccount.OnClick := sbSearchBuyAccountClick;
  497. //
  498. ebFee.Text := TAccountComp.FormatMoney(0);
  499. ebFee.OnExit:= ebCurrencyExit;
  500. memoAccounts.Lines.Clear;
  501. PageControlOpType.ActivePage := tsTransaction;
  502. end;
  503. procedure TFRMOperation.ebNewPublicKeyExit(Sender: TObject);
  504. var errors : AnsiString;
  505. begin
  506. UpdateOperationOptions(errors);
  507. end;
  508. procedure TFRMOperation.FormDestroy(Sender: TObject);
  509. begin
  510. if Assigned(FWalletKeys) then FWalletKeys.OnChanged.Remove(OnWalletKeysChanged);
  511. FreeAndNil(FSenderAccounts);
  512. end;
  513. function TFRMOperation.GetDefaultSenderAccount: TAccount;
  514. begin
  515. if FSenderAccounts.Count>=1 then Result := FNode.Operations.SafeBoxTransaction.Account( FSenderAccounts.Get(0) )
  516. else Result := CT_Account_NUL;
  517. end;
  518. procedure TFRMOperation.ebAccountKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  519. Var eb : TCustomEdit;
  520. begin
  521. If (key <> VK_F2) then exit;
  522. If Not Assigned(Sender) then exit;
  523. if Not (Sender is TCustomEdit) then exit;
  524. eb := TCustomEdit(Sender);
  525. searchAccount(eb);
  526. end;
  527. procedure TFRMOperation.searchAccount(editBox: TCustomEdit);
  528. Var F : TFRMAccountSelect;
  529. c : Cardinal;
  530. begin
  531. F := TFRMAccountSelect.Create(Self);
  532. try
  533. F.Node := FNode;
  534. F.WalletKeys := FWalletKeys;
  535. F.Filters:=editBox.Tag;
  536. If TAccountComp.AccountTxtNumberToAccountNumber(editBox.Text,c) then F.DefaultAccount := c;
  537. F.AllowSelect:=True;
  538. If F.ShowModal=MrOk then begin
  539. editBox.Text := TAccountComp.AccountNumberToAccountTxtNumber(F.GetSelected);
  540. end;
  541. finally
  542. F.Free;
  543. end;
  544. end;
  545. procedure TFRMOperation.memoPayloadClick(Sender: TObject);
  546. Var errors : AnsiString;
  547. begin
  548. if SenderAccounts.Count>0 then begin
  549. UpdatePayload(TNode.Node.Bank.SafeBox.Account(SenderAccounts.Get(0)),errors);
  550. end;
  551. end;
  552. procedure TFRMOperation.OnSenderAccountsChanged(Sender: TObject);
  553. Var errors : AnsiString;
  554. begin
  555. if SenderAccounts.Count>1 then begin
  556. ebAmount.Text := 'ALL BALANCE';
  557. ebAmount.font.Style := [fsBold];
  558. ebAmount.ReadOnly := true;
  559. end else begin
  560. ebAmount.Text := TAccountComp.FormatMoney(0);
  561. ebAmount.ReadOnly := false;
  562. ebAmount.Enabled := true;
  563. end;
  564. If SenderAccounts.Count>=1 then begin
  565. ebSignerAccount.text := TAccountComp.AccountNumberToAccountTxtNumber(SenderAccounts.Get(0));
  566. ebChangeName.Text := FNode.Operations.SafeBoxTransaction.Account(SenderAccounts.Get(0)).name;
  567. ebChangeType.Text := IntToStr(FNode.Operations.SafeBoxTransaction.Account(SenderAccounts.Get(0)).account_type);
  568. end else begin
  569. ebSignerAccount.text := '';
  570. ebChangeName.Text := '';
  571. ebChangeType.Text := '';
  572. end;
  573. UpdateAccountsInfo;
  574. UpdateOperationOptions(errors);
  575. end;
  576. procedure TFRMOperation.OnWalletKeysChanged(Sender: TObject);
  577. begin
  578. PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
  579. end;
  580. procedure TFRMOperation.PageControlOpTypeChange(Sender: TObject);
  581. var errors : AnsiString;
  582. begin
  583. UpdateOperationOptions(errors);
  584. end;
  585. procedure TFRMOperation.sbSearchBuyAccountClick(Sender: TObject);
  586. begin
  587. searchAccount(ebAccountToBuy);
  588. end;
  589. procedure TFRMOperation.sbSearchDestinationAccountClick(Sender: TObject);
  590. begin
  591. searchAccount(ebDestAccount);
  592. end;
  593. procedure TFRMOperation.sbSearchListerSellerAccountClick(Sender: TObject);
  594. begin
  595. searchAccount(ebSellerAccount);
  596. end;
  597. procedure TFRMOperation.sbSearchSignerAccountClick(Sender: TObject);
  598. begin
  599. searchAccount(ebSignerAccount);
  600. end;
  601. procedure TFRMOperation.SetDefaultFee(const Value: Int64);
  602. var wd : Boolean;
  603. begin
  604. if FDefaultFee = Value then exit;
  605. wd := FDisabled;
  606. try
  607. FDisabled := true;
  608. FDefaultFee := Value;
  609. ebFee.Text := TAccountComp.FormatMoney(value);
  610. finally
  611. FDisabled := wd;
  612. end;
  613. end;
  614. procedure TFRMOperation.SetWalletKeys(const Value: TWalletKeys);
  615. begin
  616. Try
  617. if FWalletKeys=Value then exit;
  618. if Assigned(FWalletKeys) then FWalletKeys.OnChanged.Remove(OnWalletKeysChanged);
  619. FWalletKeys := Value;
  620. if Assigned(FWalletKeys) then begin
  621. FWalletKeys.OnChanged.Add(OnWalletKeysChanged);
  622. end;
  623. Finally
  624. UpdateWalletKeys;
  625. End;
  626. end;
  627. procedure TFRMOperation.UpdateAccountsInfo;
  628. Var ld : Boolean;
  629. i : Integer;
  630. balance : int64;
  631. acc : TAccount;
  632. accountstext : String;
  633. begin
  634. ld := FDisabled;
  635. FDisabled := true;
  636. Try
  637. lblAccountCaption.Caption := 'Account';
  638. lblAccountsCount.Visible := false;
  639. lblAccountsCount.caption := inttostr(senderAccounts.Count)+' accounts';
  640. balance := 0;
  641. if SenderAccounts.Count<=0 then begin
  642. ebSenderAccount.Text := '';
  643. memoAccounts.Visible := false;
  644. ebSenderAccount.Visible := true;
  645. end else if SenderAccounts.Count=1 then begin
  646. ebSenderAccount.Text := TAccountComp.AccountNumberToAccountTxtNumber(SenderAccounts.Get(0));
  647. memoAccounts.Visible := false;
  648. ebSenderAccount.Visible := true;
  649. balance := TNode.Node.Operations.SafeBoxTransaction.Account(SenderAccounts.Get(0)).balance;
  650. end else begin
  651. // Multiple sender accounts
  652. lblAccountCaption.Caption := 'Accounts';
  653. lblAccountsCount.Visible := true;
  654. ebSenderAccount.Visible := false;
  655. accountstext := '';
  656. for i := 0 to SenderAccounts.Count - 1 do begin
  657. acc := TNode.Node.Operations.SafeBoxTransaction.Account(SenderAccounts.Get(i));
  658. balance := balance + acc.balance;
  659. if (accountstext<>'') then accountstext:=accountstext+'; ';
  660. accountstext := accountstext+TAccountComp.AccountNumberToAccountTxtNumber(acc.account)+' ('+TAccountComp.FormatMoney(acc.balance)+')';
  661. end;
  662. memoAccounts.Lines.Text := accountstext;
  663. memoAccounts.Visible := true;
  664. end;
  665. ebSenderAccount.Enabled := ebSenderAccount.Visible;
  666. lblAccountBalance.Caption := TAccountComp.FormatMoney(balance);
  667. Finally
  668. FDisabled := ld;
  669. End;
  670. end;
  671. function TFRMOperation.UpdateFee(var Fee: Int64; errors: AnsiString): Boolean;
  672. begin
  673. errors := '';
  674. if trim(ebFee.Text)<>'' then begin
  675. Result := TAccountComp.TxtToMoney(Trim(ebFee.Text),Fee);
  676. if not Result then errors := 'Invalid fee value "'+ebFee.Text+'"';
  677. end else begin
  678. Fee := 0;
  679. Result := true;
  680. end;
  681. end;
  682. procedure TFRMOperation.updateInfoClick(Sender: TObject);
  683. Var errors : AnsiString;
  684. begin
  685. UpdateOperationOptions(errors);
  686. end;
  687. function TFRMOperation.UpdateOpBuyAccount(const SenderAccount: TAccount; var AccountToBuy: TAccount; var amount: Int64; var NewPublicKey: TAccountKey; var errors: AnsiString): Boolean;
  688. var c : Cardinal;
  689. i : Integer;
  690. begin
  691. //
  692. lblBuyAccountErrors.Caption := ''; c:=0;
  693. errors := '';
  694. Try
  695. if SenderAccounts.Count<>1 then begin
  696. errors := 'Cannot buy accounts with multioperations. Use only 1 account';
  697. exit;
  698. end;
  699. If (Not TAccountComp.AccountTxtNumberToAccountNumber(ebAccountToBuy.Text,c)) then begin
  700. errors := 'Invalid account to buy '+ebAccountToBuy.Text;
  701. exit;
  702. end;
  703. If (c<0) Or (c>=FNode.Bank.AccountsCount) Or (c=SenderAccount.account) then begin
  704. errors := 'Invalid account number';
  705. exit;
  706. end;
  707. AccountToBuy := FNode.Operations.SafeBoxTransaction.Account(c);
  708. If not TAccountComp.IsAccountForSale(AccountToBuy.accountInfo) then begin
  709. errors := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(c)+' is not for sale';
  710. exit;
  711. end;
  712. If Not TAccountComp.TxtToMoney(ebBuyAmount.Text,amount) then begin
  713. errors := 'Invalid amount value';
  714. exit;
  715. end;
  716. if (AccountToBuy.accountInfo.price>amount) then begin
  717. errors := 'Account price '+TAccountComp.FormatMoney(AccountToBuy.accountInfo.price);
  718. exit;
  719. end;
  720. if (amount+DefaultFee > SenderAccount.balance) then begin
  721. errors := 'Insufficient funds';
  722. exit;
  723. end;
  724. if cbBuyNewKey.ItemIndex<0 then begin
  725. errors := 'Must select a new private key';
  726. exit;
  727. end;
  728. i := PtrInt(cbBuyNewKey.Items.Objects[cbBuyNewKey.ItemIndex]);
  729. if (i<0) Or (i>=WalletKeys.Count) then raise Exception.Create('Invalid selected key');
  730. NewPublicKey := WalletKeys.Key[i].AccountKey;
  731. If (FNode.Bank.SafeBox.CurrentProtocol=CT_PROTOCOL_1) then begin
  732. errors := 'This operation needs PROTOCOL 2 active';
  733. exit;
  734. end;
  735. Finally
  736. Result := errors = '';
  737. lblBuyAccountErrors.Caption := errors;
  738. End;
  739. end;
  740. function TFRMOperation.UpdateOpChangeInfo(const TargetAccount: TAccount; var SignerAccount : TAccount;
  741. var changeName : Boolean; var newName: AnsiString; var changeType : Boolean; var newType: Word; var errors: AnsiString): Boolean;
  742. var auxC : Cardinal;
  743. i : Integer;
  744. errCode : Integer;
  745. begin
  746. Result := false;
  747. errors := '';
  748. lblChangeInfoErrors.Caption:='';
  749. if not (PageControlOpType.ActivePage=tsChangeInfo) then exit;
  750. try
  751. if SenderAccounts.Count<>1 then begin
  752. errors := 'Cannot change info with multioperations. Use only 1 account';
  753. exit;
  754. end;
  755. if (TAccountComp.IsAccountLocked(TargetAccount.accountInfo,FNode.Bank.BlocksCount)) then begin
  756. errors := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account)+' is locked until block '+IntToStr(TargetAccount.accountInfo.locked_until_block);
  757. exit;
  758. end;
  759. // Signer:
  760. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,auxC) then begin
  761. errors := 'Invalid signer account';
  762. exit;
  763. end;
  764. if (auxC<0) Or (auxC >= FNode.Bank.AccountsCount) then begin
  765. errors := 'Signer account does not exists '+TAccountComp.AccountNumberToAccountTxtNumber(auxC);
  766. exit;
  767. end;
  768. SignerAccount := FNode.Operations.SafeBoxTransaction.Account(auxC);
  769. if (TAccountComp.IsAccountLocked(SignerAccount.accountInfo,FNode.Bank.BlocksCount)) then begin
  770. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is locked until block '+IntToStr(SignerAccount.accountInfo.locked_until_block);
  771. exit;
  772. end;
  773. if (Not TAccountComp.EqualAccountKeys(SignerAccount.accountInfo.accountKey,TargetAccount.accountInfo.accountKey)) then begin
  774. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is not ower of account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account);
  775. exit;
  776. end;
  777. If (FNode.Bank.SafeBox.CurrentProtocol=CT_PROTOCOL_1) then begin
  778. errors := 'This operation needs PROTOCOL 2 active';
  779. exit;
  780. end;
  781. // New name and type
  782. newName := LowerCase( Trim(ebChangeName.Text) );
  783. If newName<>TargetAccount.name then begin
  784. changeName:=True;
  785. If newName<>'' then begin
  786. if (Not TPCSafeBox.ValidAccountName(newName,errors)) then begin
  787. errors := '"'+newName+'" is not a valid name: '+errors;
  788. Exit;
  789. end;
  790. i := (FNode.Bank.SafeBox.FindAccountByName(newName));
  791. if (i>=0) then begin
  792. errors := 'Name "'+newName+'" is used by account '+TAccountComp.AccountNumberToAccountTxtNumber(i);
  793. Exit;
  794. end;
  795. end;
  796. end else changeName := False;
  797. val(ebChangeType.Text,newType,errCode);
  798. if (errCode>0) then begin
  799. errors := 'Invalid type '+ebChangeType.text;
  800. Exit;
  801. end;
  802. changeType := TargetAccount.account_type<>newType;
  803. //
  804. If (newName=TargetAccount.name) And (newType=TargetAccount.account_type) then begin
  805. errors := 'Account name and type are the same. Not changed';
  806. Exit;
  807. end;
  808. finally
  809. Result := errors = '';
  810. if Not Result then begin
  811. lblChangeInfoErrors.Font.Color := clRed;
  812. lblChangeInfoErrors.Caption := errors;
  813. end else begin
  814. lblChangeInfoErrors.Font.Color := clGreen;
  815. lblChangeInfoErrors.Caption := TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account)+' can be updated';
  816. end;
  817. end;
  818. end;
  819. function TFRMOperation.UpdateOpChangeKey(Const TargetAccount : TAccount; var SignerAccount : TAccount; var NewPublicKey: TAccountKey; var errors: AnsiString): Boolean;
  820. var i : Integer;
  821. auxC : Cardinal;
  822. begin
  823. Result := false;
  824. errors := '';
  825. lblChangeKeyErrors.Caption := '';
  826. lblNewOwnerErrors.Caption := '';
  827. if not (PageControlOpType.ActivePage=tsChangePrivateKey) then exit;
  828. try
  829. if rbChangeKeyWithAnother.Checked then begin
  830. if cbNewPrivateKey.ItemIndex<0 then begin
  831. errors := 'Must select a new private key';
  832. lblChangeKeyErrors.Caption := errors;
  833. exit;
  834. end;
  835. i := PtrInt(cbNewPrivateKey.Items.Objects[cbNewPrivateKey.ItemIndex]);
  836. if (i<0) Or (i>=WalletKeys.Count) then raise Exception.Create('Invalid selected key');
  837. NewPublicKey := WalletKeys.Key[i].AccountKey;
  838. end else if rbChangeKeyTransferAccountToNewOwner.Checked then begin
  839. If Not TAccountComp.AccountKeyFromImport(ebNewPublicKey.Text,NewPublicKey,errors) then begin
  840. lblNewOwnerErrors.Caption := errors;
  841. lblNewOwnerErrors.Font.Color := clRed;
  842. exit;
  843. end else begin
  844. lblNewOwnerErrors.Caption := 'New key type: '+TAccountComp.GetECInfoTxt(NewPublicKey.EC_OpenSSL_NID);
  845. lblNewOwnerErrors.Font.Color := clGreen;
  846. end;
  847. end else begin
  848. errors := 'Select a change type';
  849. lblChangeKeyErrors.Caption := errors;
  850. exit;
  851. end;
  852. If FNode.Bank.SafeBox.CurrentProtocol>=1 then begin
  853. // Signer:
  854. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,auxC) then begin
  855. errors := 'Invalid signer account';
  856. exit;
  857. end;
  858. if (auxC<0) Or (auxC >= FNode.Bank.AccountsCount) then begin
  859. errors := 'Signer account does not exists '+TAccountComp.AccountNumberToAccountTxtNumber(auxC);
  860. exit;
  861. end;
  862. SignerAccount := FNode.Operations.SafeBoxTransaction.Account(auxC);
  863. if (TAccountComp.IsAccountLocked(SignerAccount.accountInfo,FNode.Bank.BlocksCount)) then begin
  864. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is locked until block '+IntToStr(SignerAccount.accountInfo.locked_until_block);
  865. exit;
  866. end;
  867. if (Not TAccountComp.EqualAccountKeys(SignerAccount.accountInfo.accountKey,TargetAccount.accountInfo.accountKey)) then begin
  868. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is not ower of account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account);
  869. exit;
  870. end;
  871. end else SignerAccount := TargetAccount;
  872. if (TAccountComp.EqualAccountKeys(TargetAccount.accountInfo.accountKey,NewPublicKey)) then begin
  873. errors := 'New public key is the same public key';
  874. lblChangeKeyErrors.Caption := errors;
  875. lblNewOwnerErrors.Caption := errors;
  876. exit;
  877. end;
  878. finally
  879. Result := errors = '';
  880. end;
  881. end;
  882. function TFRMOperation.UpdateOpDelist(const TargetAccount : TAccount; var SignerAccount : TAccount; var errors: AnsiString): Boolean;
  883. Var auxC : Cardinal;
  884. begin
  885. lblDelistErrors.Caption := '';
  886. errors := '';
  887. Result := false;
  888. if not (PageControlOpType.ActivePage=tsDelist) then exit;
  889. try
  890. if Not TAccountComp.IsAccountForSale(TargetAccount.accountInfo) then begin
  891. errors := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account)+' is not for sale';
  892. exit;
  893. end;
  894. if (TAccountComp.IsAccountLocked(TargetAccount.accountInfo,FNode.Bank.BlocksCount)) then begin
  895. errors := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account)+' is locked until block '+IntToStr(TargetAccount.accountInfo.locked_until_block);
  896. exit;
  897. end;
  898. // Signer:
  899. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,auxC) then begin
  900. errors := 'Invalid signer account';
  901. exit;
  902. end;
  903. if (auxC<0) Or (auxC >= FNode.Bank.AccountsCount) then begin
  904. errors := 'Signer account does not exists '+TAccountComp.AccountNumberToAccountTxtNumber(auxC);
  905. exit;
  906. end;
  907. SignerAccount := FNode.Operations.SafeBoxTransaction.Account(auxC);
  908. if (TAccountComp.IsAccountLocked(SignerAccount.accountInfo,FNode.Bank.BlocksCount)) then begin
  909. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is locked until block '+IntToStr(SignerAccount.accountInfo.locked_until_block);
  910. exit;
  911. end;
  912. if (Not TAccountComp.EqualAccountKeys(SignerAccount.accountInfo.accountKey,TargetAccount.accountInfo.accountKey)) then begin
  913. errors := 'Signer account '+TAccountComp.AccountNumberToAccountTxtNumber(SignerAccount.account)+' is not ower of delisted account '+TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account);
  914. exit;
  915. end;
  916. If (FNode.Bank.SafeBox.CurrentProtocol=CT_PROTOCOL_1) then begin
  917. errors := 'This operation needs PROTOCOL 2 active';
  918. exit;
  919. end;
  920. finally
  921. Result := errors = '';
  922. if Not Result then begin
  923. lblDelistErrors.Font.Color := clRed;
  924. lblDelistErrors.Caption := errors;
  925. end else begin
  926. lblDelistErrors.Font.Color := clGreen;
  927. lblDelistErrors.Caption := TAccountComp.AccountNumberToAccountTxtNumber(TargetAccount.account)+' can be delisted';
  928. end;
  929. end;
  930. end;
  931. function TFRMOperation.UpdateOperationOptions(var errors : AnsiString) : Boolean;
  932. Var
  933. iWallet,iAcc : Integer;
  934. wk : TWalletKey;
  935. e : AnsiString;
  936. sender_account,dest_account,seller_account, account_to_buy, signer_account : TAccount;
  937. publicKey : TAccountKey;
  938. salePrice, amount : Int64;
  939. auxC : Cardinal;
  940. changeName,changeType : Boolean;
  941. newName : AnsiString;
  942. newType : Word;
  943. begin
  944. Result := false;
  945. sender_account := CT_Account_NUL;
  946. errors := '';
  947. if Not UpdateFee(FDefaultFee,errors) then exit;
  948. try
  949. bbPassword.Visible := false;
  950. bbPassword.Enabled := false;
  951. if Not Assigned(WalletKeys) then begin
  952. errors := 'No wallet keys';
  953. lblGlobalErrors.Caption := errors;
  954. exit;
  955. end;
  956. if SenderAccounts.Count=0 then begin
  957. errors := 'No sender account';
  958. lblGlobalErrors.Caption := errors;
  959. exit;
  960. end else begin
  961. for iAcc := 0 to SenderAccounts.Count - 1 do begin
  962. sender_account := TNode.Node.Bank.SafeBox.Account(SenderAccounts.Get(iAcc));
  963. iWallet := WalletKeys.IndexOfAccountKey(sender_account.accountInfo.accountKey);
  964. if (iWallet<0) then begin
  965. errors := 'Private key of account '+TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account)+' not found in wallet';
  966. lblGlobalErrors.Caption := errors;
  967. exit;
  968. end;
  969. wk := WalletKeys.Key[iWallet];
  970. if not assigned(wk.PrivateKey) then begin
  971. if wk.HasPrivateKey then begin
  972. errors := 'Wallet is password protected. Need password';
  973. bbPassword.Visible := true;
  974. bbPassword.Enabled := true;
  975. end else begin
  976. errors := 'Only public key of account '+TAccountComp.AccountNumberToAccountTxtNumber(sender_account.account)+' found in wallet. You cannot operate with this account';
  977. end;
  978. lblGlobalErrors.Caption := errors;
  979. exit;
  980. end;
  981. end;
  982. end;
  983. lblGlobalErrors.Caption := '';
  984. Finally
  985. if lblGlobalErrors.Caption<>'' then begin
  986. tsGlobalError.visible := true;
  987. tsGlobalError.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
  988. tsOperation.TabVisible := false;
  989. PageControlLocked.ActivePage := tsGlobalError;
  990. if bbPassword.CanFocus then begin
  991. ActiveControl := bbPassword;
  992. end;
  993. end else begin
  994. tsOperation.visible := true;
  995. tsOperation.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
  996. tsGlobalError.TabVisible := false;
  997. PageControlLocked.ActivePage := tsOperation;
  998. end;
  999. End;
  1000. if (PageControlOpType.ActivePage = tsTransaction) then begin
  1001. Result := UpdateOpTransaction(GetDefaultSenderAccount,dest_account,amount,errors);
  1002. end else if (PageControlOpType.ActivePage = tsChangePrivateKey) then begin
  1003. Result := UpdateOpChangeKey(GetDefaultSenderAccount,signer_account,publicKey,errors);
  1004. end else if (PageControlOpType.ActivePage = tsListForSale) then begin
  1005. Result := UpdateOpListForSale(GetDefaultSenderAccount,salePrice,seller_account,signer_account,publicKey,auxC,errors);
  1006. end else if (PageControlOpType.ActivePage = tsDelist) then begin
  1007. Result := UpdateOpDelist(GetDefaultSenderAccount,signer_account,errors);
  1008. end else if (PageControlOpType.ActivePage = tsBuyAccount) then begin
  1009. Result := UpdateOpBuyAccount(GetDefaultSenderAccount,account_to_buy,amount,publicKey,errors);
  1010. end else if (PageControlOpType.ActivePage = tsChangeInfo) then begin
  1011. Result := UpdateOpChangeInfo(GetDefaultSenderAccount,signer_account,changeName,newName,changeType,newType,errors);
  1012. end else begin
  1013. errors := 'Must select an operation';
  1014. end;
  1015. if (PageControlOpType.ActivePage=tsTransaction) then begin
  1016. rbEncryptedWithOldEC.Caption := 'Encrypted with sender public key';
  1017. rbEncryptedWithEC.Caption := 'Encrypted with destination public key';
  1018. end else if (PageControlOpType.ActivePage=tsChangePrivateKey) then begin
  1019. rbEncryptedWithOldEC.Caption := 'Encrypted with old public key';
  1020. rbEncryptedWithEC.Caption := 'Encrypted with new public key';
  1021. end else if ((PageControlOpType.ActivePage=tsListForSale) Or (PageControlOpType.ActivePage=tsDelist)) then begin
  1022. rbEncryptedWithOldEC.Caption := 'Encrypted with target public key';
  1023. rbEncryptedWithEC.Caption := 'Encrypted with signer public key';
  1024. end else if (PageControlOpType.ActivePage=tsBuyAccount) then begin
  1025. rbEncryptedWithOldEC.Caption := 'Encrypted with buyer public key';
  1026. rbEncryptedWithEC.Caption := 'Encrypted with target public key';
  1027. end;
  1028. ebSignerAccount.Enabled:= ((PageControlOpType.ActivePage=tsChangePrivateKey) And (FNode.Bank.SafeBox.CurrentProtocol>=CT_PROTOCOL_2))
  1029. Or (PageControlOpType.ActivePage=tsChangeInfo)
  1030. Or (PageControlOpType.ActivePage=tsListForSale)
  1031. Or (PageControlOpType.ActivePage=tsDelist);
  1032. sbSearchSignerAccount.Enabled:=ebSignerAccount.Enabled;
  1033. lblSignerAccount.Enabled := ebSignerAccount.Enabled;
  1034. //
  1035. UpdatePayload(sender_account, e);
  1036. end;
  1037. function TFRMOperation.UpdateOpListForSale(const TargetAccount: TAccount;
  1038. var SalePrice: Int64; var SellerAccount, SignerAccount: TAccount;
  1039. var NewOwnerPublicKey: TAccountKey; var LockedUntilBlock: Cardinal;
  1040. var errors: AnsiString): Boolean;
  1041. var auxC : Cardinal;
  1042. begin
  1043. Result := False;
  1044. SalePrice := 0; SellerAccount := CT_Account_NUL;
  1045. NewOwnerPublicKey := CT_TECDSA_Public_Nul;
  1046. LockedUntilBlock := 0; errors := '';
  1047. if (PageControlOpType.ActivePage <> tsListForSale) then exit;
  1048. lblListAccountErrors.Caption := '';
  1049. Try
  1050. if (rbListAccountForPublicSale.Checked) Or (rbListAccountForPrivateSale.Checked) then begin
  1051. if rbListAccountForPublicSale.Checked then begin
  1052. lblSaleNewOwnerPublicKey.Enabled := false;
  1053. ebSaleNewOwnerPublicKey.Enabled := false;
  1054. ebSaleLockedUntilBlock.Enabled := false;
  1055. lblSaleLockedUntilBlock.Enabled := false;
  1056. end else if rbListAccountForPrivateSale.Checked then begin
  1057. lblSaleNewOwnerPublicKey.Enabled := true;
  1058. ebSaleNewOwnerPublicKey.Enabled := true;
  1059. ebSaleLockedUntilBlock.Enabled := true;
  1060. lblSaleLockedUntilBlock.Enabled := true;
  1061. end;
  1062. if not TAccountComp.TxtToMoney(ebSalePrice.Text,salePrice) then begin
  1063. errors := 'Invalid price';
  1064. exit;
  1065. end;
  1066. // Signer:
  1067. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,auxC) then begin
  1068. errors := 'Invalid signer account';
  1069. exit;
  1070. end;
  1071. if (auxC<0) Or (auxC >= FNode.Bank.AccountsCount) then begin
  1072. errors := 'Signer account does not exists '+TAccountComp.AccountNumberToAccountTxtNumber(auxC);
  1073. exit;
  1074. end;
  1075. SignerAccount := FNode.Operations.SafeBoxTransaction.Account(auxC);
  1076. // Seller
  1077. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSellerAccount.Text,auxC) then begin
  1078. errors := 'Invalid seller account';
  1079. exit;
  1080. end;
  1081. if (auxC<0) Or (auxC >= FNode.Bank.AccountsCount) then begin
  1082. errors := 'Seller account does not exists '+TAccountComp.AccountNumberToAccountTxtNumber(auxC);
  1083. exit;
  1084. end;
  1085. if (auxC=TargetAccount.account) then begin
  1086. errors := 'Seller account cannot be same account';
  1087. exit;
  1088. end;
  1089. SellerAccount := FNode.Operations.SafeBoxTransaction.Account(auxC);
  1090. if rbListAccountForPrivateSale.Checked then begin
  1091. lblSaleNewOwnerPublicKey.Enabled := true;
  1092. ebSaleNewOwnerPublicKey.Enabled := true;
  1093. ebSaleLockedUntilBlock.Enabled := true;
  1094. lblSaleLockedUntilBlock.Enabled := true;
  1095. If Not TAccountComp.AccountKeyFromImport(ebSaleNewOwnerPublicKey.Text,NewOwnerPublicKey,errors) then begin
  1096. errors := 'Public key: '+errors;
  1097. exit;
  1098. end else begin
  1099. lblListAccountErrors.Font.Color := clGreen;
  1100. lblListAccountErrors.Caption := 'New key type: '+TAccountComp.GetECInfoTxt(NewOwnerPublicKey.EC_OpenSSL_NID);
  1101. end;
  1102. if TAccountComp.EqualAccountKeys(NewOwnerPublicKey,TargetAccount.accountInfo.accountKey) then begin
  1103. errors := 'New public key for private sale is the same public key';
  1104. Exit;
  1105. end;
  1106. LockedUntilBlock := StrToIntDef(ebSaleLockedUntilBlock.Text,0);
  1107. if LockedUntilBlock=0 then begin
  1108. errors := 'Insert locking block';
  1109. exit;
  1110. end;
  1111. end;
  1112. If (FNode.Bank.SafeBox.CurrentProtocol=CT_PROTOCOL_1) then begin
  1113. errors := 'This operation needs PROTOCOL 2 active';
  1114. exit;
  1115. end;
  1116. end else begin
  1117. lblSaleNewOwnerPublicKey.Enabled := false;
  1118. ebSaleNewOwnerPublicKey.Enabled := false;
  1119. ebSaleLockedUntilBlock.Enabled := false;
  1120. lblSaleLockedUntilBlock.Enabled := false;
  1121. errors := 'Select a sale type';
  1122. exit;
  1123. end;
  1124. Finally
  1125. Result := errors='';
  1126. if errors<>'' then begin
  1127. lblListAccountErrors.Caption := errors;
  1128. lblListAccountErrors.Font.Color := clRed;
  1129. end;
  1130. End;
  1131. end;
  1132. function TFRMOperation.UpdateOpTransaction(const SenderAccount: TAccount; var DestAccount: TAccount; var amount: Int64; var errors: AnsiString): Boolean;
  1133. Var c : Cardinal;
  1134. begin
  1135. Result := False;
  1136. errors := '';
  1137. lblTransactionErrors.Caption := '';
  1138. if PageControlOpType.ActivePage<>tsTransaction then exit;
  1139. if not (TAccountComp.AccountTxtNumberToAccountNumber(ebDestAccount.Text,c)) then begin
  1140. errors := 'Invalid dest. account ('+ebDestAccount.Text+')';
  1141. lblTransactionErrors.Caption := errors;
  1142. exit;
  1143. end;
  1144. if (c<0) Or (c>=TNode.Node.Bank.AccountsCount) then begin
  1145. errors := 'Invalid dest. account ('+TAccountComp.AccountNumberToAccountTxtNumber(c)+')';
  1146. lblTransactionErrors.Caption := errors;
  1147. exit;
  1148. end;
  1149. DestAccount := TNode.Node.Operations.SafeBoxTransaction.Account(c);
  1150. if SenderAccounts.Count=1 then begin
  1151. if not TAccountComp.TxtToMoney(ebAmount.Text,amount) then begin
  1152. errors := 'Invalid amount ('+ebAmount.Text+')';
  1153. lblTransactionErrors.Caption := errors;
  1154. exit;
  1155. end;
  1156. end else amount := 0; // ALL BALANCE
  1157. if DestAccount.account=SenderAccount.account then begin
  1158. errors := 'Sender and dest account are the same';
  1159. lblTransactionErrors.Caption := errors;
  1160. exit;
  1161. end;
  1162. if (SenderAccounts.Count=1) then begin
  1163. if (SenderAccount.balance<(amount+FDefaultFee)) then begin
  1164. errors := 'Insufficient funds';
  1165. lblTransactionErrors.Caption := errors;
  1166. exit;
  1167. end;
  1168. end;
  1169. Result := True;
  1170. end;
  1171. function TFRMOperation.UpdatePayload(const SenderAccount: TAccount;
  1172. var errors: AnsiString): Boolean;
  1173. Var payload_u : AnsiString;
  1174. payload_encrypted : TRawBytes;
  1175. account : TAccount;
  1176. public_key : TAccountKey;
  1177. dest_account_number : Cardinal;
  1178. i : Integer;
  1179. valid : Boolean;
  1180. wk : TWalletKey;
  1181. begin
  1182. valid := false;
  1183. payload_encrypted := '';
  1184. FEncodedPayload := '';
  1185. errors := 'Unknown error';
  1186. payload_u := memoPayload.Lines.Text;
  1187. try
  1188. if (payload_u='') then begin
  1189. valid := true;
  1190. exit;
  1191. end;
  1192. if (rbEncryptedWithOldEC.Checked) then begin
  1193. // Use sender
  1194. errors := 'Error encrypting';
  1195. account := FNode.Operations.SafeBoxTransaction.Account(SenderAccount.account);
  1196. payload_encrypted := ECIESEncrypt(account.accountInfo.accountKey,payload_u);
  1197. valid := payload_encrypted<>'';
  1198. end else if (rbEncryptedWithEC.Checked) then begin
  1199. errors := 'Error encrypting';
  1200. if (PageControlOpType.ActivePage=tsTransaction) or (PageControlOpType.ActivePage=tsListForSale) or (PageControlOpType.ActivePage=tsDelist)
  1201. or (PageControlOpType.ActivePage=tsBuyAccount) then begin
  1202. // With dest public key
  1203. If (PageControlOpType.ActivePage=tsTransaction) then begin
  1204. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebDestAccount.Text,dest_account_number) then begin
  1205. errors := 'Invalid dest account number';
  1206. exit;
  1207. end;
  1208. end else if (PageControlOpType.ActivePage=tsListForSale) then begin
  1209. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,dest_account_number) then begin
  1210. errors := 'Invalid signer account number';
  1211. exit;
  1212. end;
  1213. end else if (PageControlOpType.ActivePage=tsDelist) then begin
  1214. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebSignerAccount.Text,dest_account_number) then begin
  1215. errors := 'Invalid signer account number';
  1216. exit;
  1217. end;
  1218. end else if (PageControlOpType.ActivePage=tsBuyAccount) then begin
  1219. If Not TAccountComp.AccountTxtNumberToAccountNumber(ebAccountToBuy.Text,dest_account_number) then begin
  1220. errors := 'Invalid account to buy number';
  1221. exit;
  1222. end;
  1223. end else begin
  1224. errors := 'ERROR DEV 20170512-1';
  1225. exit;
  1226. end;
  1227. if (dest_account_number<0) or (dest_account_number>=FNode.Bank.AccountsCount) then begin
  1228. errors := 'Invalid payload encrypted account number: '+TAccountComp.AccountNumberToAccountTxtNumber(dest_account_number);
  1229. exit;
  1230. end;
  1231. account := FNode.Operations.SafeBoxTransaction.Account(dest_account_number);
  1232. payload_encrypted := ECIESEncrypt(account.accountInfo.accountKey,payload_u);
  1233. valid := payload_encrypted<>'';
  1234. end else if (PageControlOpType.ActivePage=tsChangePrivateKey) then begin
  1235. if (rbChangeKeyWithAnother.Checked) then begin
  1236. // With new key generated
  1237. if (cbNewPrivateKey.ItemIndex>=0) then begin
  1238. i := PtrInt(cbNewPrivateKey.Items.Objects[cbNewPrivateKey.ItemIndex]);
  1239. if (i>=0) then public_key := WalletKeys.Key[i].AccountKey;
  1240. end else begin
  1241. errors := 'Must select a private key';
  1242. exit;
  1243. end;
  1244. end else if (rbChangeKeyTransferAccountToNewOwner.Checked) then begin
  1245. If Not TAccountComp.AccountKeyFromImport(ebNewPublicKey.Text,public_key,errors) then begin
  1246. errors := 'Public key: '+errors;
  1247. exit;
  1248. end;
  1249. end else begin
  1250. errors := 'Must select change type';
  1251. exit;
  1252. end;
  1253. if public_key.EC_OpenSSL_NID<>CT_Account_NUL.accountInfo.accountKey.EC_OpenSSL_NID then begin
  1254. payload_encrypted := ECIESEncrypt(public_key,payload_u);
  1255. valid := payload_encrypted<>'';
  1256. end else begin
  1257. valid := false;
  1258. errors := 'Selected private key is not valid to encode';
  1259. exit;
  1260. end;
  1261. end else begin
  1262. errors := 'This operation does not allow this kind of payload';
  1263. end;
  1264. end else if (rbEncrptedWithPassword.Checked) then begin
  1265. payload_encrypted := TAESComp.EVP_Encrypt_AES256(payload_u,ebEncryptPassword.Text);
  1266. valid := payload_encrypted<>'';
  1267. end else if (rbNotEncrypted.Checked) then begin
  1268. payload_encrypted := payload_u;
  1269. valid := true;
  1270. end else begin
  1271. errors := 'Must select an encryption option for payload';
  1272. end;
  1273. finally
  1274. if valid then begin
  1275. if length(payload_encrypted)>CT_MaxPayloadSize then begin
  1276. valid := false;
  1277. errors := 'Payload size is bigger than '+inttostr(CT_MaxPayloadSize)+' ('+Inttostr(length(payload_encrypted))+')';
  1278. end;
  1279. end;
  1280. if valid then begin
  1281. lblEncryptionErrors.Caption := '';
  1282. lblPayloadLength.Caption := Format('(%db -> %db)',[length(payload_u),length(payload_encrypted)]);
  1283. end else begin
  1284. lblEncryptionErrors.Caption := errors;
  1285. lblPayloadLength.Caption := Format('(%db -> ?)',[length(payload_u)]);
  1286. end;
  1287. FEncodedPayload := payload_encrypted;
  1288. Result := valid;
  1289. end;
  1290. end;
  1291. procedure TFRMOperation.UpdateWalletKeys;
  1292. Var i : Integer;
  1293. wk : TWalletKey;
  1294. s : String;
  1295. begin
  1296. cbNewPrivateKey.items.BeginUpdate;
  1297. cbBuyNewKey.Items.BeginUpdate;
  1298. Try
  1299. cbNewPrivateKey.Items.Clear;
  1300. cbBuyNewKey.Items.Clear;
  1301. if Not Assigned(FWalletKeys) then exit;
  1302. For i:=0 to FWalletKeys.Count-1 do begin
  1303. wk := FWalletKeys.Key[i];
  1304. if (wk.Name='') then begin
  1305. s := TCrypto.ToHexaString( TAccountComp.AccountKey2RawString(wk.AccountKey));
  1306. end else begin
  1307. s := wk.Name;
  1308. end;
  1309. if Not Assigned(wk.PrivateKey) then s := s + '(*)';
  1310. cbNewPrivateKey.Items.AddObject(s,TObject(i));
  1311. cbBuyNewKey.Items.AddObject(s,TObject(i));
  1312. end;
  1313. cbNewPrivateKey.Sorted := true;
  1314. cbBuyNewKey.Sorted := true;
  1315. Finally
  1316. cbNewPrivateKey.Items.EndUpdate;
  1317. cbBuyNewKey.Items.EndUpdate;
  1318. End;
  1319. updateInfoClick(Nil);
  1320. memoPayloadClick(Nil);
  1321. end;
  1322. end.