Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
EDalerClient.cs
1using EDaler.Events;
2using System;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
7using Waher.Content;
9using Waher.Events;
15using Waher.Script;
16
17namespace EDaler
18{
23 {
27 public const string NamespaceEDaler = "http://waher.se/Schema/eDaler.xsd";
28
29 internal const string EDalerBalanceKeyPrefix = "EDaler.Balance.";
30 internal const string EDalerRemoteKeyPrefix = "EDaler.Remote.Key.";
31
32 private readonly ContractsClient contractsClient;
33 private readonly string componentAddress;
34 private LastBalance balance = null;
35
43 : base(Client)
44 {
45 this.componentAddress = ComponentAddress;
46 this.contractsClient = ContractsClient;
47
48 Client.RegisterMessageHandler("balance", NamespaceEDaler, this.BalanceEventHandler, true);
49 Client.RegisterMessageHandler("buyEDalerOptionsClientUrl", NamespaceEDaler, this.BuyEDalerOptionsClientUrlEventHandler, false);
50 Client.RegisterMessageHandler("buyEDalerOptionsCompleted", NamespaceEDaler, this.BuyEDalerOptionsCompletedEventHandler, false);
51 Client.RegisterMessageHandler("buyEDalerOptionsError", NamespaceEDaler, this.BuyEDalerOptionsErrorEventHandler, false);
52 Client.RegisterMessageHandler("buyEDalerClientUrl", NamespaceEDaler, this.BuyEDalerClientUrlEventHandler, false);
53 Client.RegisterMessageHandler("buyEDalerCompleted", NamespaceEDaler, this.BuyEDalerCompletedEventHandler, false);
54 Client.RegisterMessageHandler("buyEDalerError", NamespaceEDaler, this.BuyEDalerErrorEventHandler, false);
55 Client.RegisterMessageHandler("sellEDalerOptionsClientUrl", NamespaceEDaler, this.SellEDalerOptionsClientUrlEventHandler, false);
56 Client.RegisterMessageHandler("sellEDalerOptionsCompleted", NamespaceEDaler, this.SellEDalerOptionsCompletedEventHandler, false);
57 Client.RegisterMessageHandler("sellEDalerOptionsError", NamespaceEDaler, this.SellEDalerOptionsErrorEventHandler, false);
58 Client.RegisterMessageHandler("sellEDalerClientUrl", NamespaceEDaler, this.SellEDalerClientUrlEventHandler, false);
59 Client.RegisterMessageHandler("sellEDalerCompleted", NamespaceEDaler, this.SellEDalerCompletedEventHandler, false);
60 Client.RegisterMessageHandler("sellEDalerError", NamespaceEDaler, this.SellEDalerErrorEventHandler, false);
61 }
62
66 public override void Dispose()
67 {
68 this.client.UnregisterMessageHandler("balance", NamespaceEDaler, this.BalanceEventHandler, true);
69 this.client.UnregisterMessageHandler("buyEDalerOptionsClientUrl", NamespaceEDaler, this.BuyEDalerOptionsClientUrlEventHandler, false);
70 this.client.UnregisterMessageHandler("buyEDalerOptionsCompleted", NamespaceEDaler, this.BuyEDalerOptionsCompletedEventHandler, false);
71 this.client.UnregisterMessageHandler("buyEDalerOptionsError", NamespaceEDaler, this.BuyEDalerOptionsErrorEventHandler, false);
72 this.client.UnregisterMessageHandler("buyEDalerClientUrl", NamespaceEDaler, this.BuyEDalerClientUrlEventHandler, false);
73 this.client.UnregisterMessageHandler("buyEDalerCompleted", NamespaceEDaler, this.BuyEDalerCompletedEventHandler, false);
74 this.client.UnregisterMessageHandler("buyEDalerError", NamespaceEDaler, this.BuyEDalerErrorEventHandler, false);
75 this.client.UnregisterMessageHandler("sellEDalerOptionsClientUrl", NamespaceEDaler, this.SellEDalerOptionsClientUrlEventHandler, false);
76 this.client.UnregisterMessageHandler("sellEDalerOptionsCompleted", NamespaceEDaler, this.SellEDalerOptionsCompletedEventHandler, false);
77 this.client.UnregisterMessageHandler("sellEDalerOptionsError", NamespaceEDaler, this.SellEDalerOptionsErrorEventHandler, false);
78 this.client.UnregisterMessageHandler("sellEDalerClientUrl", NamespaceEDaler, this.SellEDalerClientUrlEventHandler, false);
79 this.client.UnregisterMessageHandler("sellEDalerCompleted", NamespaceEDaler, this.SellEDalerCompletedEventHandler, false);
80 this.client.UnregisterMessageHandler("sellEDalerError", NamespaceEDaler, this.SellEDalerErrorEventHandler, false);
81
82 base.Dispose();
83 }
84
88 public string ComponentAddress => this.componentAddress;
89
93 public override string[] Extensions => new string[] { };
94
95 #region Balance
96
102 public Task GetBalance(EventHandlerAsync<BalanceIqResultEventArgs> Callback, object State)
103 {
104 return this.GetBalance(this.componentAddress, Callback, State);
105 }
106
113 public Task GetBalance(string ComponentAddress, EventHandlerAsync<BalanceIqResultEventArgs> Callback, object State)
114 {
115 StringBuilder Xml = new StringBuilder();
116
117 Xml.Append("<balance xmlns='");
118 Xml.Append(NamespaceEDaler);
119 Xml.Append("'/>");
120
121 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
122 {
123 XmlElement E;
125
126 if (e.Ok &&
127 !((E = e.FirstElement) is null) &&
128 E.LocalName == "balance" &&
129 E.NamespaceURI == NamespaceEDaler)
130 {
131 Balance = await this.ParseBalance(E);
132
133 if (Balance is null)
134 e.Ok = false;
135 else
136 await this.BalanceReported(Balance);
137 }
138 else
139 {
140 e.Ok = false;
141 Balance = null;
142 }
143
144 await Callback.Raise(this, new BalanceIqResultEventArgs(e, Balance));
145
146 }, State);
147 }
148
149 private async Task BalanceReported(Balance Balance)
150 {
151 string LastBalanceKey = EDalerBalanceKeyPrefix + this.client.BareJID;
152 bool Changed = false;
153
154 this.balance ??= await RuntimeSettings.GetAsync(LastBalanceKey, (object)null) as LastBalance;
155
156 if (this.balance is null ||
157 this.balance.Timestamp < Balance.Timestamp ||
158 (this.balance.Timestamp < Balance.Timestamp.AddSeconds(1) && this.balance.Balance != Balance.Amount))
159 {
160 if (this.balance is null)
161 {
162 this.balance = new LastBalance()
163 {
165 Currency = Balance.Currency,
166 Timestamp = Balance.Timestamp
167 };
168 }
169 else
170 {
171 this.balance.Balance = Balance.Amount;
172 this.balance.Currency = Balance.Currency;
173 this.balance.Timestamp = Balance.Timestamp;
174 }
175
176 Changed = true;
177 }
178
179 if (!(this.balance.Pending is null) && !(Balance.Event is null))
180 {
181 List<PendingPayment> Pending = new List<PendingPayment>();
182 DateTime Today = DateTime.Today;
183
184 foreach (PendingPayment Payment in this.balance.Pending)
185 {
186 if (Payment.Expires.AddDays(1) < Today || Payment.Id == Balance.Event.TransactionId)
187 {
188 Changed = true;
189 continue;
190 }
191
192 Pending.Add(Payment);
193 }
194
195 if (Changed)
196 this.balance.Pending = Pending.ToArray();
197 }
198
199 if (Changed)
200 await RuntimeSettings.SetAsync(LastBalanceKey, this.balance);
201 }
202
207 public Task<Balance> GetBalanceAsync()
208 {
209 return this.GetBalanceAsync(this.componentAddress);
210 }
211
217 public async Task<Balance> GetBalanceAsync(string ComponentAddress)
218 {
219 TaskCompletionSource<Balance> Result = new TaskCompletionSource<Balance>();
220
221 await this.GetBalance(ComponentAddress, async (Sender, e) =>
222 {
223 if (e.Ok)
224 {
225 await this.BalanceReported(e.Balance);
226 Result.TrySetResult(e.Balance);
227 }
228 else
229 Result.TrySetException(e.StanzaError ?? new Exception("Unable to get current balance."));
230
231 }, null);
232
233 return await Result.Task;
234 }
235
236 private async Task BalanceEventHandler(object Sender, MessageEventArgs e)
237 {
238 if (e.From != this.componentAddress)
239 return;
240
241 Balance Balance = await this.ParseBalance(e.Content);
242 await this.BalanceReported(Balance);
243
244 await this.BalanceUpdated.Raise(this, new BalanceEventArgs(Balance));
245 }
246
247 private async Task<Balance> ParseBalance(XmlElement Xml)
248 {
249 CaseInsensitiveString Currency = null;
250 DateTime? Timestamp = null;
251 decimal? Balance = null;
252 decimal Reserved = 0;
253 AccountEvent Event = null;
254
255 foreach (XmlAttribute Attr in Xml.Attributes)
256 {
257 switch (Attr.Name)
258 {
259 case "amount":
260 if (!CommonTypes.TryParse(Attr.Value, out decimal d))
261 return null;
262
263 Balance = d;
264 break;
265
266 case "reserved":
267 if (!CommonTypes.TryParse(Attr.Value, out d))
268 return null;
269
270 Reserved = d;
271 break;
272
273 case "currency":
274 Currency = Attr.Value;
275 break;
276
277 case "timestamp":
278 if (!XML.TryParse(Attr.Value, out DateTime TP))
279 return null;
280
281 Timestamp = TP;
282 break;
283 }
284 }
285
286 if (!Balance.HasValue || Currency is null || !Timestamp.HasValue)
287 return null;
288
289 foreach (XmlNode N in Xml.ChildNodes)
290 {
291 if (N is XmlElement E && E.LocalName == "event" && E.NamespaceURI == NamespaceEDaler)
292 {
293 Event = await AccountEvent.FromXml(E, this);
294 break;
295 }
296 }
297
298 return new Balance(Timestamp.Value, Balance.Value, Reserved, Currency, Event);
299 }
300
305 public event EventHandlerAsync<BalanceEventArgs> BalanceUpdated = null;
306
307 #endregion
308
309 #region eDaler URIs
310
317 public Task SendEDalerUri(string Uri, EventHandlerAsync<TransactionEventArgs> Callback, object State)
318 {
319 return this.SendEDalerUri(this.componentAddress, Uri, Callback, State);
320 }
321
329 public Task SendEDalerUri(string ComponentAddress, string Uri, EventHandlerAsync<TransactionEventArgs> Callback, object State)
330 {
331 StringBuilder Xml = new StringBuilder();
332
333 Xml.Append("<uri xmlns=\"");
334 Xml.Append(NamespaceEDaler);
335 Xml.Append("\">");
336 Xml.Append(XML.Encode(Uri));
337 Xml.Append("</uri>");
338
339 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
340 {
341 if (Callback is null)
342 return;
343
345
346 if (e.Ok)
347 {
348 if (e.FirstElement is null ||
349 e.FirstElement.LocalName != "tr" ||
350 e.FirstElement.NamespaceURI != NamespaceEDaler)
351 {
352 e.Ok = false;
353 }
354 else
355 Transaction = Transaction.FromXml(e.FirstElement);
356 }
357
358 await Callback.Raise(this, new TransactionEventArgs(e, Transaction));
359
360 }, State);
361 }
362
367 public Task<Transaction> SendEDalerUriAsync(string Uri)
368 {
369 return this.SendEDalerUriAsync(this.componentAddress, Uri);
370 }
371
377 public async Task<Transaction> SendEDalerUriAsync(string ComponentAddress, string Uri)
378 {
379 TaskCompletionSource<Transaction> Result = new TaskCompletionSource<Transaction>();
380
381 await this.SendEDalerUri(ComponentAddress, Uri, (Sender, e) =>
382 {
383 if (e.Ok)
384 Result.TrySetResult(e.Transaction);
385 else if (!(e.StanzaError is null))
386 Result.TrySetException(e.StanzaError);
387 else
388 Result.TrySetException(new Exception("Unable to process eDaler URI."));
389
390 return Task.CompletedTask;
391 }, null);
392
393 return await Result.Task;
394 }
395
396 #endregion
397
398 #region eDaler Account events
399
406 public Task GetAccountEvents(int MaxEvents, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
407 {
408 return this.GetAccountEvents(this.componentAddress, MaxEvents, DateTime.MaxValue, Callback, State);
409 }
410
418 public Task GetAccountEvents(string ComponentAddress, int MaxEvents, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
419 {
420 return this.GetAccountEvents(ComponentAddress, MaxEvents, DateTime.MaxValue, Callback, State);
421 }
422
430 public Task GetAccountEvents(int MaxEvents, DateTime From, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
431 {
432 return this.GetAccountEvents(this.componentAddress, MaxEvents, From, Callback, State);
433 }
434
443 public Task GetAccountEvents(string ComponentAddress, int MaxEvents, DateTime From, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
444 {
445 StringBuilder Xml = new StringBuilder();
446
447 Xml.Append("<events xmlns=\"");
448 Xml.Append(NamespaceEDaler);
449 Xml.Append("\" maxCount=\"");
450 Xml.Append(MaxEvents.ToString());
451
452 if (From != DateTime.MaxValue)
453 {
454 Xml.Append("\" from=\"");
455 Xml.Append(XML.Encode(From));
456 }
457
458 Xml.Append("\"/>");
459
460 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
461 {
462 List<AccountEvent> Events = new List<AccountEvent>();
463 bool More = false;
464
465 if (e.Ok)
466 {
467 if (e.FirstElement is null ||
468 e.FirstElement.LocalName != "events" ||
469 e.FirstElement.NamespaceURI != NamespaceEDaler)
470 {
471 e.Ok = false;
472 }
473 else
474 {
475 foreach (XmlNode N in e.FirstElement.ChildNodes)
476 {
477 if (!(N is XmlElement E) || E.NamespaceURI != NamespaceEDaler)
478 continue;
479
480 switch (E.LocalName)
481 {
482 case "event":
483 AccountEvent Event = await AccountEvent.FromXml(E, this);
484 Events.Add(Event);
485 break;
486
487 case "more":
488 More = true;
489 break;
490 }
491 }
492
493 await Callback.Raise(this, new AccountEventsEventArgs(Events.ToArray(), More, e));
494 }
495 }
496 }, State);
497 }
498
499
505 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents)
506 {
507 return this.GetAccountEventsAsync(this.componentAddress, MaxEvents, DateTime.MaxValue);
508 }
509
516 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents)
517 {
518 return this.GetAccountEventsAsync(ComponentAddress, MaxEvents, DateTime.MaxValue);
519 }
520
527 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents, DateTime From)
528 {
529 return this.GetAccountEventsAsync(this.componentAddress, MaxEvents, From);
530 }
531
539 public async Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents, DateTime From)
540 {
541 TaskCompletionSource<(AccountEvent[], bool)> Result = new TaskCompletionSource<(AccountEvent[], bool)>();
542
543 await this.GetAccountEvents(ComponentAddress, MaxEvents, From, async (Sender, e) =>
544 {
545 if (e.Ok)
546 {
547 try
548 {
549 if (this.balance is null)
550 await this.GetBalanceAsync();
551
552 if (!(this.balance.Pending is null) && this.balance.Pending.Length > 0)
553 {
554 Dictionary<Guid, PendingPayment> Pending = new Dictionary<Guid, PendingPayment>();
555 DateTime Today = DateTime.Today;
556 bool Changed = false;
557
558 foreach (PendingPayment Payment in this.balance.Pending)
559 {
560 if (Payment.Expires.AddDays(1) < Today)
561 Changed = true;
562 else
563 Pending[Payment.Id] = Payment;
564 }
565
566 foreach (AccountEvent Event in e.Events)
567 {
568 if (Pending.Remove(Event.TransactionId))
569 Changed = true;
570 }
571
572 if (Changed)
573 {
574 PendingPayment[] Pending2 = new PendingPayment[Pending.Count];
575 Pending.Values.CopyTo(Pending2, 0);
576 this.balance.Pending = Pending2;
577
578 await RuntimeSettings.SetAsync(EDalerBalanceKeyPrefix + this.client.BareJID, this.balance);
579 }
580 }
581
582 Result.TrySetResult((e.Events, e.More));
583 }
584 catch (Exception ex)
585 {
586 Result.TrySetException(ex);
587 }
588 }
589 else if (!(e.StanzaError is null))
590 Result.TrySetException(e.StanzaError);
591 else
592 Result.TrySetException(new Exception("Unable to process eDaler URI."));
593
594 }, null);
595
596 return await Result.Task;
597 }
598
599 #endregion
600
601 #region Payment URIs
602
611 public Task<string> CreateFullPaymentUri(decimal Amount, decimal? AmountExtra,
612 CaseInsensitiveString Currency, int ValidNrDays)
613 {
614 return this.CreateFullPaymentUri(string.Empty, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
615 }
616
626 public Task<string> CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra,
627 CaseInsensitiveString Currency, int ValidNrDays)
628 {
629 return this.CreateFullPaymentUri(ToBareJid, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
630 }
631
642 public async Task<string> CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra,
643 CaseInsensitiveString Currency, int ValidNrDays, string Message)
644 {
645 await this.ValidatePaymentArguments(Amount, AmountExtra, Currency, ValidNrDays);
646
647 StringBuilder Uri = new StringBuilder();
648 DateTime Created = DateTime.UtcNow;
649 DateTime Expires = DateTime.Today.AddDays(ValidNrDays);
650 Guid Id = Guid.NewGuid();
651
652 Uri.Append("edaler:id=");
653 Uri.Append(Id.ToString());
654 Uri.Append(";f=");
655 Uri.Append(XML.Encode(this.client.BareJID));
656
657 if (!string.IsNullOrEmpty(ToBareJid))
658 {
659 if (ToBareJid.IndexOf('@') < 0)
660 {
661 Uri.Append(";xx="); // Destruction (payment to operator)
662 Uri.Append(XML.Encode(ToBareJid));
663 }
664 else
665 {
666 Uri.Append(";t=");
667 Uri.Append(XML.Encode(ToBareJid));
668 }
669 }
670
671 Uri.Append(";am=");
672 Uri.Append(CommonTypes.Encode(Amount));
673
674 if (AmountExtra.HasValue)
675 {
676 Uri.Append(";amx=");
677 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
678 }
679
680 Uri.Append(";cu=");
681 Uri.Append(XML.Encode(Currency));
682 Uri.Append(";cr=");
683 Uri.Append(XML.Encode(Created, false));
684 Uri.Append(";ex=");
685 Uri.Append(XML.Encode(Expires, true));
686
687 if (!string.IsNullOrEmpty(Message))
688 {
689 Uri.Append(";m=");
690 Uri.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(Message)));
691 }
692
693 await this.SignAndCheckBalance(Uri, Amount, AmountExtra, Currency, Id, Expires, ToBareJid);
694
695 return Uri.ToString();
696 }
697
698 private async Task ValidatePaymentArguments(decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
699 {
700 if (ValidNrDays <= 0)
701 throw new ArgumentException("Must be a positive integer.", nameof(ValidNrDays));
702
703 if (Amount <= 0)
704 throw new ArgumentException("Amount must be positive.", nameof(Amount));
705
706 if (AmountExtra.HasValue && AmountExtra.Value <= 0)
707 throw new ArgumentException("Amount must be positive.", nameof(AmountExtra));
708
709 if (this.balance is null)
710 await this.GetBalanceAsync();
711
712 LastBalance Balance = this.balance;
713 if (Currency != Balance.Currency) // TODO: Currency conversion, if supported by neuron
714 {
715 throw new ArgumentException("Currency in payment (" + Currency.Value +
716 ") does not correspond to currency of wallet (" + Balance.Currency.Value + ").",
717 nameof(Currency));
718 }
719 }
720
721 private async Task SignAndCheckBalance(StringBuilder Uri, decimal Amount, decimal? AmountExtra, string Currency,
722 Guid Id, DateTime Expires, string To)
723 {
724 byte[] PreSign = Encoding.UTF8.GetBytes(Uri.ToString());
725 byte[] Signature = await this.contractsClient.SignAsync(PreSign, SignWith.LatestApprovedId);
726
727 Uri.Append(";s=");
728 Uri.Append(Convert.ToBase64String(Signature));
729
731 DateTime Today = DateTime.Today;
732 List<PendingPayment> Pending;
733 decimal PendingAmount;
734
735 do
736 {
737 Balance = this.balance;
738 Pending = new List<PendingPayment>();
739 PendingAmount = 0;
740
741 if (!(Balance.Pending is null))
742 {
743 foreach (PendingPayment PendingPayment in Balance.Pending)
744 {
745 if (PendingPayment.Expires.AddDays(1) >= Today)
746 {
747 Pending.Add(PendingPayment);
748 PendingAmount += PendingPayment.Amount;
749 }
750 }
751 }
752
753 if (Amount + (AmountExtra ?? 0) + PendingAmount > Balance.Balance)
754 {
755 StringBuilder Msg = new StringBuilder();
756
757 Msg.Append("Amount larger than current balance. Amount: ");
758 Msg.Append(Amount.ToString());
759
760 if (AmountExtra.HasValue)
761 {
762 Msg.Append(". Extra: ");
763 Msg.Append(AmountExtra.Value.ToString());
764 }
765
766 if (PendingAmount > 0)
767 {
768 Msg.Append(". Pending: ");
769 Msg.Append(PendingAmount.ToString());
770 }
771
772 Msg.Append(". Balance: ");
773 Msg.Append(Balance.Balance.ToString());
774
775 Msg.Append(". Difference: ");
776 Msg.Append((Balance.Balance - Amount - (AmountExtra ?? 0) - PendingAmount).ToString());
777
778 throw new InvalidOperationException(Msg.ToString());
779 }
780
781 Pending.Add(new PendingPayment()
782 {
783 Id = Id,
784 Expires = Expires,
785 Currency = Currency,
786 Amount = Amount + (AmountExtra ?? 0),
787 From = this.client.BareJID,
788 To = To,
789 Uri = Uri.ToString()
790 });
791
792 Balance.Pending = Pending.ToArray();
793
794 await RuntimeSettings.SetAsync(EDalerBalanceKeyPrefix + this.client.BareJID, Balance);
795 }
796 while (this.balance != Balance);
797 }
798
808 public Task<string> CreateFullPaymentUri(LegalIdentity ToLegalId, decimal Amount, decimal? AmountExtra,
809 CaseInsensitiveString Currency, int ValidNrDays)
810 {
811 return this.CreateFullPaymentUri(ToLegalId, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
812 }
813
825 public async Task<string> CreateFullPaymentUri(LegalIdentity RecipientLegalId,
826 decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency,
827 int ValidNrDays, string PrivateMessage)
828 {
829 if (RecipientLegalId is null)
830 throw new ArgumentNullException("Recipient Legal ID cannot be null.", nameof(RecipientLegalId));
831
832 if (!RecipientLegalId.HasClientPublicKey)
833 throw new ArgumentNullException("Recipient Legal ID lacks a public key.", nameof(RecipientLegalId));
834
835 await this.ValidatePaymentArguments(Amount, AmountExtra, Currency, ValidNrDays);
836
837 StringBuilder Uri = new StringBuilder();
838 DateTime Created = DateTime.UtcNow;
839 DateTime Expires = DateTime.Today.AddDays(ValidNrDays);
840 Guid Id = Guid.NewGuid();
841
842 byte[] MessageBin = Encoding.UTF8.GetBytes(PrivateMessage ?? string.Empty);
843 (byte[] EncryptedMessage, byte[] LocalPublicKey) = this.contractsClient.Encrypt(MessageBin, Id.ToByteArray(), RecipientLegalId.ClientPubKey, RecipientLegalId.ClientKeyName);
844
845 await RuntimeSettings.SetAsync(EDalerRemoteKeyPrefix + RecipientLegalId.Id, Convert.ToBase64String(RecipientLegalId.ClientPubKey));
846 string FromLegalId = await this.contractsClient.GetLatestApprovedLegalId(LocalPublicKey);
847
848 Uri.Append("edaler:id=");
849 Uri.Append(Id.ToString());
850
851 if (FromLegalId is null)
852 {
853 Uri.Append(";f=");
854 Uri.Append(XML.Encode(this.client.BareJID));
855 }
856 else
857 {
858 Uri.Append(";fi=");
859 Uri.Append(XML.Encode(FromLegalId));
860 }
861
862 Uri.Append(";ti=");
863 Uri.Append(XML.Encode(RecipientLegalId.Id));
864 Uri.Append(";am=");
865 Uri.Append(CommonTypes.Encode(Amount));
866
867 if (AmountExtra.HasValue)
868 {
869 Uri.Append(";amx=");
870 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
871 }
872
873 Uri.Append(";cu=");
874 Uri.Append(XML.Encode(Currency));
875 Uri.Append(";cr=");
876 Uri.Append(XML.Encode(Created, false));
877 Uri.Append(";ex=");
878 Uri.Append(XML.Encode(Expires, true));
879
880 if (!string.IsNullOrEmpty(PrivateMessage))
881 {
882 Uri.Append(";em=");
883 Uri.Append(Convert.ToBase64String(EncryptedMessage));
884 Uri.Append(";ep=");
885 Uri.Append(Convert.ToBase64String(LocalPublicKey));
886 }
887
888 await this.SignAndCheckBalance(Uri, Amount, AmountExtra, Currency, Id, Expires, RecipientLegalId.Id);
889
890 return Uri.ToString();
891 }
892
902 public string CreateIncompletePayMeUri(string BareJid, decimal? Amount, decimal? AmountExtra, string Currency, string Message)
903 {
904 return this.CreateIncompletePayMeUri(BareJid, "t", Amount, AmountExtra, Currency, Message);
905 }
906
918 public string CreateIncompletePayMeUri(LegalIdentity Id, decimal? Amount, decimal? AmountExtra,
919 string Currency, string PrivateMessage)
920 {
921 return this.CreateIncompletePayMeUri(Id.Id, "ti", Amount, AmountExtra, Currency, PrivateMessage);
922 }
923
924 private string CreateIncompletePayMeUri(string To, string ToType, decimal? Amount, decimal? AmountExtra,
925 string Currency, string Message)
926 {
927 StringBuilder Uri = new StringBuilder();
928
929 Uri.Append("edaler:cu=");
930 Uri.Append(Currency);
931
932 if (Amount.HasValue)
933 {
934 Uri.Append(";am=");
935 Uri.Append(CommonTypes.Encode(Amount.Value));
936 }
937
938 if (AmountExtra.HasValue)
939 {
940 Uri.Append(";amx=");
941 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
942 }
943
944 Uri.Append(';');
945 Uri.Append(ToType);
946 Uri.Append('=');
947 Uri.Append(To);
948
949 if (!string.IsNullOrEmpty(Message))
950 {
951 Uri.Append(";m=");
952 Uri.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(Message)));
953 }
954
955 return Uri.ToString();
956 }
957
966 public string DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey,
967 Guid TransactionId, bool LocalIsRecipient)
968 {
969 if (EncryptedMessage is null)
970 return string.Empty;
971
972 if (PublicKey is null)
973 return Encoding.UTF8.GetString(EncryptedMessage);
974
975 try
976 {
977 byte[] Decrypted;
978
979 if (PublicKey is null)
980 Decrypted = EncryptedMessage;
981 else if (LocalIsRecipient)
982 {
983 Decrypted = this.contractsClient.DecryptReceivedMessage(EncryptedMessage, PublicKey,
984 TransactionId.ToByteArray());
985 }
986 else
987 {
988 Decrypted = this.contractsClient.DecryptSentMessage(EncryptedMessage, PublicKey,
989 TransactionId.ToByteArray());
990 }
991
992 return Encoding.UTF8.GetString(Decrypted);
993 }
994 catch (Exception)
995 {
996 return string.Empty;
997 }
998 }
999
1009 public async Task<string> DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey,
1010 Guid TransactionId, string RemoteEndPoint, bool LocalIsRecipient)
1011 {
1012 if (!string.IsNullOrEmpty(RemoteEndPoint) && PublicKey is null)
1013 {
1014 string RemotePublicKey = await RuntimeSettings.GetAsync(EDalerRemoteKeyPrefix + RemoteEndPoint, string.Empty);
1015
1016 if (!string.IsNullOrEmpty(RemotePublicKey))
1017 {
1018 try
1019 {
1020 PublicKey = Convert.FromBase64String(RemotePublicKey);
1021 }
1022 catch (Exception ex)
1023 {
1024 Log.Exception(ex);
1025 }
1026 }
1027 }
1028
1029 return this.DecryptMessage(EncryptedMessage, PublicKey, TransactionId, LocalIsRecipient);
1030 }
1031
1032 #endregion
1033
1034 #region Pending Payments
1035
1040 public async Task<(decimal, string, PendingPayment[])> GetPendingPayments()
1041 {
1042 if (this.balance is null)
1043 await this.GetBalanceAsync();
1044
1045 List<PendingPayment> PendingPayments = new List<PendingPayment>();
1046 DateTime Today = DateTime.Today;
1047 LastBalance Balance = this.balance;
1048 decimal PendingAmount = 0;
1049
1050 if (!(Balance.Pending is null))
1051 {
1052 foreach (PendingPayment PendingPayment in Balance.Pending)
1053 {
1054 if (PendingPayment.Expires.AddDays(1) >= Today)
1055 {
1056 PendingPayments.Add(new PendingPayment()
1057 {
1058 Id = PendingPayment.Id,
1059 Expires = PendingPayment.Expires,
1060 Currency = PendingPayment.Currency,
1061 Amount = PendingPayment.Amount,
1062 From = PendingPayment.From,
1063 To = PendingPayment.To,
1064 Uri = PendingPayment.Uri
1065 });
1066
1067 PendingAmount += PendingPayment.Amount;
1068 }
1069 }
1070 }
1071
1072 return (PendingAmount, Balance.Currency, PendingPayments.ToArray());
1073 }
1074
1075 #endregion
1076
1077 #region Service Providers for buying eDaler
1078
1084 public Task GetServiceProvidersForBuyingEDaler(EventHandlerAsync<BuyEDalerServiceProvidersEventArgs> Callback, object State)
1085 {
1086 return this.GetServiceProvidersForBuyingEDaler(this.componentAddress, Callback, State);
1087 }
1088
1095 public Task GetServiceProvidersForBuyingEDaler(string ComponentAddress,
1096 EventHandlerAsync<BuyEDalerServiceProvidersEventArgs> Callback, object State)
1097 {
1098 StringBuilder Xml = new StringBuilder();
1099
1100 Xml.Append("<buyEDalerProviders xmlns='");
1101 Xml.Append(NamespaceEDaler);
1102 Xml.Append("'/>");
1103
1104 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1105 {
1106 List<IBuyEDalerServiceProvider> Providers = null;
1107 XmlElement E;
1108
1109 if (e.Ok &&
1110 !((E = e.FirstElement) is null) &&
1111 E.LocalName == "providers" &&
1112 E.NamespaceURI == NamespaceEDaler)
1113 {
1114 Providers = new List<IBuyEDalerServiceProvider>();
1115
1116 foreach (XmlNode N in E.ChildNodes)
1117 {
1118 if (N is XmlElement E2 &&
1119 E2.LocalName == "provider" &&
1120 E2.NamespaceURI == NamespaceEDaler)
1121 {
1122 IBuyEDalerServiceProvider Provider = this.ParseServiceProvider<BuyEDalerServiceProvider>(E2);
1123
1124 if (!(Provider is null))
1125 Providers.Add(Provider);
1126 }
1127 }
1128 }
1129 else
1130 e.Ok = false;
1131
1132 await Callback.Raise(this, new BuyEDalerServiceProvidersEventArgs(e, Providers?.ToArray()));
1133
1134 }, State);
1135 }
1136
1137 private T ParseServiceProvider<T>(XmlElement Xml)
1138 where T : IServiceProviderWithTemplate, new()
1139 {
1140 string Id = null;
1141 string Type = null;
1142 string Name = null;
1143 string IconUrl = null;
1144 string TemplateId = null;
1145 int IconWidth = -1;
1146 int IconHeight = -1;
1147
1148 foreach (XmlAttribute Attr in Xml.Attributes)
1149 {
1150 switch (Attr.Name)
1151 {
1152 case "id":
1153 Id = Attr.Value;
1154 break;
1155
1156 case "type":
1157 Type = Attr.Value;
1158 break;
1159
1160 case "name":
1161 Name = Attr.Value;
1162 break;
1163
1164 case "iconUrl":
1165 IconUrl = Attr.Value;
1166 break;
1167
1168 case "iconWidth":
1169 if (!int.TryParse(Attr.Value, out int i))
1170 return default;
1171
1172 IconWidth = i;
1173 break;
1174
1175 case "iconHeight":
1176 if (!int.TryParse(Attr.Value, out i))
1177 return default;
1178
1179 IconHeight = i;
1180 break;
1181
1182 case "templateId":
1183 TemplateId = Attr.Value;
1184 break;
1185 }
1186 }
1187
1188 if (Id is null || Type is null || Name is null)
1189 return default;
1190
1191 if (string.IsNullOrEmpty(IconUrl))
1192 {
1193 T Temp = new T();
1194 return (T)Temp.Create(Id, Type, Name, TemplateId);
1195 }
1196 else
1197 {
1198 if (IconWidth < 0 || IconHeight < 0)
1199 return default;
1200
1201 T Temp = new T();
1202 return (T)Temp.Create(Id, Type, Name, IconUrl, IconWidth, IconHeight, TemplateId);
1203 }
1204 }
1205
1209 public Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
1210 {
1211 return this.GetServiceProvidersForBuyingEDalerAsync(this.componentAddress);
1212 }
1213
1218 public async Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync(string ComponentAddress)
1219 {
1220 TaskCompletionSource<IBuyEDalerServiceProvider[]> Providers = new TaskCompletionSource<IBuyEDalerServiceProvider[]>();
1221
1222 await this.GetServiceProvidersForBuyingEDaler(ComponentAddress, (Sender, e) =>
1223 {
1224 if (e.Ok)
1225 Providers.TrySetResult(e.ServiceProviders);
1226 else
1227 Providers.TrySetException(e.StanzaError ?? new Exception("Unable to get service providers."));
1228
1229 return Task.CompletedTask;
1230
1231 }, null);
1232
1233 return await Providers.Task;
1234 }
1235
1236 #endregion
1237
1238 #region Service Providers for selling eDaler
1239
1245 public Task GetServiceProvidersForSellingEDaler(EventHandlerAsync<SellEDalerServiceProvidersEventArgs> Callback, object State)
1246 {
1247 return this.GetServiceProvidersForSellingEDaler(this.componentAddress, Callback, State);
1248 }
1249
1256 public Task GetServiceProvidersForSellingEDaler(string ComponentAddress,
1257 EventHandlerAsync<SellEDalerServiceProvidersEventArgs> Callback, object State)
1258 {
1259 StringBuilder Xml = new StringBuilder();
1260
1261 Xml.Append("<sellEDalerProviders xmlns='");
1262 Xml.Append(NamespaceEDaler);
1263 Xml.Append("'/>");
1264
1265 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1266 {
1267 List<ISellEDalerServiceProvider> Providers = null;
1268 XmlElement E;
1269
1270 if (e.Ok &&
1271 !((E = e.FirstElement) is null) &&
1272 E.LocalName == "providers" &&
1273 E.NamespaceURI == NamespaceEDaler)
1274 {
1275 Providers = new List<ISellEDalerServiceProvider>();
1276
1277 foreach (XmlNode N in E.ChildNodes)
1278 {
1279 if (N is XmlElement E2 &&
1280 E2.LocalName == "provider" &&
1281 E2.NamespaceURI == NamespaceEDaler)
1282 {
1283 ISellEDalerServiceProvider Provider = this.ParseServiceProvider<SellEDalerServiceProvider>(E2);
1284
1285 if (!(Provider is null))
1286 Providers.Add(Provider);
1287 }
1288 }
1289 }
1290 else
1291 e.Ok = false;
1292
1293 await Callback.Raise(this, new SellEDalerServiceProvidersEventArgs(e, Providers?.ToArray()));
1294
1295 }, State);
1296 }
1297
1301 public Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
1302 {
1303 return this.GetServiceProvidersForSellingEDalerAsync(this.componentAddress);
1304 }
1305
1310 public async Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync(string ComponentAddress)
1311 {
1312 TaskCompletionSource<ISellEDalerServiceProvider[]> Providers = new TaskCompletionSource<ISellEDalerServiceProvider[]>();
1313
1314 await this.GetServiceProvidersForSellingEDaler(ComponentAddress, (Sender, e) =>
1315 {
1316 if (e.Ok)
1317 Providers.TrySetResult(e.ServiceProviders);
1318 else
1319 Providers.TrySetException(e.StanzaError ?? new Exception("Unable to get service providers."));
1320
1321 return Task.CompletedTask;
1322
1323 }, null);
1324
1325 return await Providers.Task;
1326 }
1327
1328 #endregion
1329
1330 #region Initiation of getting Payment options for buying eDaler using smart contracts
1331
1339 public Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider,
1340 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1341 {
1342 return this.InitiateGetOptionsBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Callback, State);
1343 }
1344
1353 public Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1354 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1355 {
1356 return this.InitiateGetOptionsBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, null, null, null, null, Callback, State);
1357 }
1358
1370 public Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider,
1371 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1372 {
1373 return this.InitiateGetOptionsBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
1374 }
1375
1388 public Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1389 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1390 {
1391 if (!string.IsNullOrEmpty(SuccessUrl))
1392 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
1393
1394 if (!string.IsNullOrEmpty(FailureUrl))
1395 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
1396
1397 if (!string.IsNullOrEmpty(CancelUrl))
1398 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
1399
1400 StringBuilder Xml = new StringBuilder();
1401
1402 Xml.Append("<initiateGetOptionsBuyEDaler xmlns='");
1403 Xml.Append(NamespaceEDaler);
1404 Xml.Append("' serviceId='");
1405 Xml.Append(XML.Encode(ServiceId));
1406 Xml.Append("' serviceProvider='");
1407 Xml.Append(XML.Encode(ServiceProvider));
1408
1409 if (!string.IsNullOrEmpty(TransactionId))
1410 {
1411 Xml.Append("' tid='");
1412 Xml.Append(XML.Encode(TransactionId));
1413 }
1414
1415 if (!string.IsNullOrEmpty(SuccessUrl))
1416 {
1417 Xml.Append("' successUrl='");
1418 Xml.Append(XML.Encode(SuccessUrl));
1419 }
1420
1421 if (!string.IsNullOrEmpty(FailureUrl))
1422 {
1423 Xml.Append("' failureUrl='");
1424 Xml.Append(XML.Encode(FailureUrl));
1425 }
1426
1427 if (!string.IsNullOrEmpty(CancelUrl))
1428 {
1429 Xml.Append("' cancelUrl='");
1430 Xml.Append(XML.Encode(CancelUrl));
1431 }
1432
1433 Xml.Append("'/>");
1434
1435 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1436 {
1437 TransactionId = null;
1438 XmlElement E;
1439
1440 if (e.Ok &&
1441 !((E = e.FirstElement) is null) &&
1442 E.LocalName == "transaction" &&
1443 E.NamespaceURI == NamespaceEDaler)
1444 {
1445 TransactionId = XML.Attribute(E, "tid");
1446 }
1447 else
1448 e.Ok = false;
1449
1450 await Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
1451
1452 }, State);
1453 }
1454
1463 public Task<string> InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider)
1464 {
1465 return this.InitiateGetOptionsBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, null, null, null, null);
1466 }
1467
1480 public Task<string> InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider,
1481 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1482 {
1483 return this.InitiateGetOptionsBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
1484 }
1485
1499 public async Task<string> InitiateGetOptionsBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
1500 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1501 {
1502 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
1503
1504 await this.InitiateGetOptionsBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
1505 (Sender, e) =>
1506 {
1507 if (e.Ok)
1508 Result.TrySetResult(e.TransactionId);
1509 else
1510 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
1511
1512 return Task.CompletedTask;
1513 }, null);
1514
1515 return await Result.Task;
1516 }
1517
1518 private Task BuyEDalerOptionsClientUrlEventHandler(object Sender, MessageEventArgs e)
1519 {
1520 string TransactionId = XML.Attribute(e.Content, "tid");
1521 string Url = XML.Attribute(e.Content, "url");
1522
1523 return this.BuyEDalerOptionsClientUrlReceived.Raise(this, new BuyEDalerClientUrlEventArgs(e, TransactionId, Url));
1524 }
1525
1532 public event EventHandlerAsync<BuyEDalerClientUrlEventArgs> BuyEDalerOptionsClientUrlReceived;
1533
1534 private async Task BuyEDalerOptionsCompletedEventHandler(object Sender, MessageEventArgs e)
1535 {
1536 string TransactionId = XML.Attribute(e.Content, "tid");
1537 List<Dictionary<CaseInsensitiveString, object>> Options = new List<Dictionary<CaseInsensitiveString, object>>();
1538
1539 foreach (XmlNode N in e.Content.ChildNodes)
1540 {
1541 if (N is XmlElement E && E.LocalName == "option" && E.NamespaceURI == NamespaceEDaler)
1542 {
1543 Dictionary<CaseInsensitiveString, object> Option = new Dictionary<CaseInsensitiveString, object>();
1545
1546 foreach (XmlNode N2 in E.ChildNodes)
1547 {
1548 if (N2 is XmlElement E2 && E2.LocalName == "variable" && E2.NamespaceURI == NamespaceEDaler)
1549 {
1550 string Name = XML.Attribute(E2, "name");
1551 object Value = await ParseVariable(E2, Variables);
1552
1553 Option[Name] = Value;
1554 }
1555 }
1556
1557 Options.Add(Option);
1558 }
1559 }
1560
1561 await this.BuyEDalerOptionsCompleted.Raise(this, new PaymentOptionsEventArgs(e, TransactionId, Options.ToArray()));
1562 }
1563
1564 private async static Task<object> ParseVariable(XmlElement VariableDefinition, Variables Variables)
1565 {
1566 object Value = null;
1567
1568 foreach (XmlNode N2 in VariableDefinition.ChildNodes)
1569 {
1570 if (!(N2 is XmlElement E2))
1571 continue;
1572
1573 switch (E2.LocalName)
1574 {
1575 case "null":
1576 Value = null;
1577 break;
1578
1579 case "dbl":
1580 if (CommonTypes.TryParse(E2.InnerText, out double dbl))
1581 Value = dbl;
1582 break;
1583
1584 case "fl":
1585 if (CommonTypes.TryParse(E2.InnerText, out float fl))
1586 Value = fl;
1587 break;
1588
1589 case "dec":
1590 if (CommonTypes.TryParse(E2.InnerText, out decimal dec))
1591 Value = dec;
1592 break;
1593
1594 case "i8":
1595 if (sbyte.TryParse(E2.InnerText, out sbyte i8))
1596 Value = i8;
1597 break;
1598
1599 case "i16":
1600 if (short.TryParse(E2.InnerText, out short i16))
1601 Value = i16;
1602 break;
1603
1604 case "i32":
1605 if (int.TryParse(E2.InnerText, out int i32))
1606 Value = i32;
1607 break;
1608
1609 case "i64":
1610 if (long.TryParse(E2.InnerText, out long i64))
1611 Value = i64;
1612 break;
1613
1614 case "ui8":
1615 if (byte.TryParse(E2.InnerText, out byte ui8))
1616 Value = ui8;
1617 break;
1618
1619 case "ui16":
1620 if (ushort.TryParse(E2.InnerText, out ushort ui16))
1621 Value = ui16;
1622 break;
1623
1624 case "ui32":
1625 if (uint.TryParse(E2.InnerText, out uint ui32))
1626 Value = ui32;
1627 break;
1628
1629 case "ui64":
1630 if (ulong.TryParse(E2.InnerText, out ulong ui64))
1631 Value = ui64;
1632 break;
1633
1634 case "b":
1635 if (CommonTypes.TryParse(E2.InnerText, out bool b))
1636 Value = b;
1637 break;
1638
1639 case "dt":
1640 if (XML.TryParse(E2.InnerText, out DateTime TP))
1641 Value = TP;
1642 break;
1643
1644 case "dto":
1645 if (XML.TryParse(E2.InnerText, out DateTimeOffset TPO))
1646 Value = TPO;
1647 break;
1648
1649 case "ts":
1650 if (TimeSpan.TryParse(E2.InnerText, out TimeSpan TS))
1651 Value = TS;
1652 break;
1653
1654 case "d":
1655 if (Duration.TryParse(E2.InnerText, out Duration D))
1656 Value = D;
1657 break;
1658
1659 case "s":
1660 Value = E2.InnerText;
1661 break;
1662
1663 case "exp":
1664 try
1665 {
1666 Expression Exp = new Expression(E2.InnerText);
1667 Value = await Exp.EvaluateAsync(Variables);
1668 }
1669 catch (Exception)
1670 {
1671 Value = E2.InnerText;
1672 }
1673 break;
1674 }
1675 }
1676
1677 return Value;
1678 }
1679
1684 public event EventHandlerAsync<PaymentOptionsEventArgs> BuyEDalerOptionsCompleted;
1685
1686 private Task BuyEDalerOptionsErrorEventHandler(object Sender, MessageEventArgs e)
1687 {
1688 string TransactionId = XML.Attribute(e.Content, "tid");
1689 string Error = e.Content.InnerText;
1690
1691 return this.BuyEDalerOptionsError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
1692 }
1693
1698 public event EventHandlerAsync<PaymentErrorEventArgs> BuyEDalerOptionsError;
1699
1700 #endregion
1701
1702 #region Initiation of getting Payment options for selling eDaler using smart contracts
1703
1711 public Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider,
1712 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1713 {
1714 return this.InitiateGetOptionsSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Callback, State);
1715 }
1716
1725 public Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1726 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1727 {
1728 return this.InitiateGetOptionsSellEDaler(ComponentAddress, ServiceId, ServiceProvider, null, null, null, null, Callback, State);
1729 }
1730
1742 public Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider,
1743 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1744 {
1745 return this.InitiateGetOptionsSellEDaler(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
1746 }
1747
1760 public Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1761 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1762 {
1763 if (!string.IsNullOrEmpty(SuccessUrl))
1764 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
1765
1766 if (!string.IsNullOrEmpty(FailureUrl))
1767 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
1768
1769 if (!string.IsNullOrEmpty(CancelUrl))
1770 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
1771
1772 StringBuilder Xml = new StringBuilder();
1773
1774 Xml.Append("<initiateGetOptionsSellEDaler xmlns='");
1775 Xml.Append(NamespaceEDaler);
1776 Xml.Append("' serviceId='");
1777 Xml.Append(XML.Encode(ServiceId));
1778 Xml.Append("' serviceProvider='");
1779 Xml.Append(XML.Encode(ServiceProvider));
1780
1781 if (!string.IsNullOrEmpty(TransactionId))
1782 {
1783 Xml.Append("' tid='");
1784 Xml.Append(XML.Encode(TransactionId));
1785 }
1786
1787 if (!string.IsNullOrEmpty(SuccessUrl))
1788 {
1789 Xml.Append("' successUrl='");
1790 Xml.Append(XML.Encode(SuccessUrl));
1791 }
1792
1793 if (!string.IsNullOrEmpty(FailureUrl))
1794 {
1795 Xml.Append("' failureUrl='");
1796 Xml.Append(XML.Encode(FailureUrl));
1797 }
1798
1799 if (!string.IsNullOrEmpty(CancelUrl))
1800 {
1801 Xml.Append("' cancelUrl='");
1802 Xml.Append(XML.Encode(CancelUrl));
1803 }
1804
1805 Xml.Append("'/>");
1806
1807 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
1808 {
1809 TransactionId = null;
1810 XmlElement E;
1811
1812 if (e.Ok &&
1813 !((E = e.FirstElement) is null) &&
1814 E.LocalName == "transaction" &&
1815 E.NamespaceURI == NamespaceEDaler)
1816 {
1817 TransactionId = XML.Attribute(E, "tid");
1818 }
1819 else
1820 e.Ok = false;
1821
1822 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
1823
1824 }, State);
1825 }
1826
1835 public Task<string> InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider)
1836 {
1837 return this.InitiateGetOptionsSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, null, null, null, null);
1838 }
1839
1852 public Task<string> InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider,
1853 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1854 {
1855 return this.InitiateGetOptionsSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
1856 }
1857
1871 public async Task<string> InitiateGetOptionsSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
1872 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1873 {
1874 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
1875
1876 await this.InitiateGetOptionsSellEDaler(ComponentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
1877 (Sender, e) =>
1878 {
1879 if (e.Ok)
1880 Result.TrySetResult(e.TransactionId);
1881 else
1882 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
1883
1884 return Task.CompletedTask;
1885 }, null);
1886
1887 return await Result.Task;
1888 }
1889
1890 private Task SellEDalerOptionsClientUrlEventHandler(object Sender, MessageEventArgs e)
1891 {
1892 string TransactionId = XML.Attribute(e.Content, "tid");
1893 string Url = XML.Attribute(e.Content, "url");
1894
1895 return this.SellEDalerOptionsClientUrlReceived.Raise(this, new SellEDalerClientUrlEventArgs(e, TransactionId, Url));
1896 }
1897
1904 public event EventHandlerAsync<SellEDalerClientUrlEventArgs> SellEDalerOptionsClientUrlReceived;
1905
1906 private async Task SellEDalerOptionsCompletedEventHandler(object Sender, MessageEventArgs e)
1907 {
1908 string TransactionId = XML.Attribute(e.Content, "tid");
1909 List<Dictionary<CaseInsensitiveString, object>> Options = new List<Dictionary<CaseInsensitiveString, object>>();
1910
1911 foreach (XmlNode N in e.Content.ChildNodes)
1912 {
1913 if (N is XmlElement E && E.LocalName == "option" && E.NamespaceURI == NamespaceEDaler)
1914 {
1915 Dictionary<CaseInsensitiveString, object> Option = new Dictionary<CaseInsensitiveString, object>();
1917
1918 foreach (XmlNode N2 in E.ChildNodes)
1919 {
1920 if (N2 is XmlElement E2 && E2.LocalName == "variable" && E2.NamespaceURI == NamespaceEDaler)
1921 {
1922 string Name = XML.Attribute(E2, "name");
1923 object Value = await ParseVariable(E2, Variables);
1924
1925 Option[Name] = Value;
1926 }
1927 }
1928
1929 Options.Add(Option);
1930 }
1931 }
1932
1933 await this.SellEDalerOptionsCompleted.Raise(this, new PaymentOptionsEventArgs(e, TransactionId, Options.ToArray()));
1934 }
1935
1940 public event EventHandlerAsync<PaymentOptionsEventArgs> SellEDalerOptionsCompleted;
1941
1942 private Task SellEDalerOptionsErrorEventHandler(object Sender, MessageEventArgs e)
1943 {
1944 string TransactionId = XML.Attribute(e.Content, "tid");
1945 string Error = e.Content.InnerText;
1946
1947 return this.SellEDalerOptionsError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
1948 }
1949
1954 public event EventHandlerAsync<PaymentErrorEventArgs> SellEDalerOptionsError;
1955
1956 #endregion
1957
1958 #region Initiation of buying eDaler using non-contract based services
1959
1969 public Task InitiateBuyEDaler(string ServiceId, string ServiceProvider,
1970 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1971 {
1972 return this.InitiateBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, Callback, State);
1973 }
1974
1985 public Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1986 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1987 {
1988 return this.InitiateBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null, Callback, State);
1989 }
1990
2004 public Task InitiateBuyEDaler(string ServiceId, string ServiceProvider,
2005 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2006 {
2007 return this.InitiateBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
2008 }
2009
2024 public Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2025 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2026 {
2027 if (!string.IsNullOrEmpty(SuccessUrl))
2028 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
2029
2030 if (!string.IsNullOrEmpty(FailureUrl))
2031 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
2032
2033 if (!string.IsNullOrEmpty(CancelUrl))
2034 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
2035
2036 StringBuilder Xml = new StringBuilder();
2037
2038 Xml.Append("<initiateBuyEDaler xmlns='");
2039 Xml.Append(NamespaceEDaler);
2040 Xml.Append("' serviceId='");
2041 Xml.Append(XML.Encode(ServiceId));
2042 Xml.Append("' serviceProvider='");
2043 Xml.Append(XML.Encode(ServiceProvider));
2044 Xml.Append("' amount='");
2045 Xml.Append(CommonTypes.Encode(Amount));
2046 Xml.Append("' currency='");
2047 Xml.Append(XML.Encode(Currency));
2048
2049 if (!string.IsNullOrEmpty(TransactionId))
2050 {
2051 Xml.Append("' tid='");
2052 Xml.Append(XML.Encode(TransactionId));
2053 }
2054
2055 if (!string.IsNullOrEmpty(SuccessUrl))
2056 {
2057 Xml.Append("' successUrl='");
2058 Xml.Append(XML.Encode(SuccessUrl));
2059 }
2060
2061 if (!string.IsNullOrEmpty(FailureUrl))
2062 {
2063 Xml.Append("' failureUrl='");
2064 Xml.Append(XML.Encode(FailureUrl));
2065 }
2066
2067 if (!string.IsNullOrEmpty(CancelUrl))
2068 {
2069 Xml.Append("' cancelUrl='");
2070 Xml.Append(XML.Encode(CancelUrl));
2071 }
2072
2073 Xml.Append("'/>");
2074
2075 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
2076 {
2077 TransactionId = null;
2078 XmlElement E;
2079
2080 if (e.Ok &&
2081 !((E = e.FirstElement) is null) &&
2082 E.LocalName == "transaction" &&
2083 E.NamespaceURI == NamespaceEDaler)
2084 {
2085 TransactionId = XML.Attribute(E, "tid");
2086 }
2087 else
2088 e.Ok = false;
2089
2090 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
2091
2092 }, State);
2093 }
2094
2105 public Task<string> InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
2106 {
2107 return this.InitiateBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency);
2108 }
2109
2121 public Task<string> InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2122 decimal Amount, string Currency)
2123 {
2124 return this.InitiateBuyEDalerAsync(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null);
2125 }
2126
2141 public Task<string> InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider,
2142 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2143 {
2144 return this.InitiateBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
2145 }
2146
2162 public async Task<string> InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2163 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2164 {
2165 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
2166
2167 await this.InitiateBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
2168 (Sender, e) =>
2169 {
2170 if (e.Ok)
2171 Result.TrySetResult(e.TransactionId);
2172 else
2173 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
2174
2175 return Task.CompletedTask;
2176 }, null);
2177
2178 return await Result.Task;
2179 }
2180
2181 private Task BuyEDalerClientUrlEventHandler(object Sender, MessageEventArgs e)
2182 {
2183 string TransactionId = XML.Attribute(e.Content, "tid");
2184 string Url = XML.Attribute(e.Content, "url");
2185
2186 return this.BuyEDalerClientUrlReceived.Raise(this, new BuyEDalerClientUrlEventArgs(e, TransactionId, Url));
2187 }
2188
2194 public event EventHandlerAsync<BuyEDalerClientUrlEventArgs> BuyEDalerClientUrlReceived;
2195
2196 private Task BuyEDalerCompletedEventHandler(object Sender, MessageEventArgs e)
2197 {
2198 string TransactionId = XML.Attribute(e.Content, "tid");
2199 string Currency = XML.Attribute(e.Content, "currency");
2200 decimal Amount = XML.Attribute(e.Content, "amount", 0M);
2201
2202 return this.BuyEDalerCompleted.Raise(this, new PaymentCompletedEventArgs(e, TransactionId, Amount, Currency));
2203 }
2204
2209 public event EventHandlerAsync<PaymentCompletedEventArgs> BuyEDalerCompleted;
2210
2211 private Task BuyEDalerErrorEventHandler(object Sender, MessageEventArgs e)
2212 {
2213 string TransactionId = XML.Attribute(e.Content, "tid");
2214 string Error = e.Content.InnerText;
2215
2216 return this.BuyEDalerError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
2217 }
2218
2223 public event EventHandlerAsync<PaymentErrorEventArgs> BuyEDalerError;
2224
2225 #endregion
2226
2227 #region Initiation of selling eDaler using non-contract based services
2228
2238 public Task InitiateSellEDaler(string ServiceId, string ServiceProvider,
2239 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2240 {
2241 return this.InitiateSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, Callback, State);
2242 }
2243
2254 public Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2255 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2256 {
2257 return this.InitiateSellEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null, Callback, State);
2258 }
2259
2273 public Task InitiateSellEDaler(string ServiceId, string ServiceProvider,
2274 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl,
2275 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2276 {
2277 return this.InitiateSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
2278 }
2279
2294 public Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2295 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl,
2296 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2297 {
2298 if (!string.IsNullOrEmpty(SuccessUrl))
2299 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
2300
2301 if (!string.IsNullOrEmpty(FailureUrl))
2302 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
2303
2304 if (!string.IsNullOrEmpty(CancelUrl))
2305 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
2306
2307 StringBuilder Xml = new StringBuilder();
2308
2309 Xml.Append("<initiateSellEDaler xmlns='");
2310 Xml.Append(NamespaceEDaler);
2311 Xml.Append("' serviceId='");
2312 Xml.Append(XML.Encode(ServiceId));
2313 Xml.Append("' serviceProvider='");
2314 Xml.Append(XML.Encode(ServiceProvider));
2315 Xml.Append("' amount='");
2316 Xml.Append(CommonTypes.Encode(Amount));
2317 Xml.Append("' currency='");
2318 Xml.Append(XML.Encode(Currency));
2319
2320 if (!string.IsNullOrEmpty(TransactionId))
2321 {
2322 Xml.Append("' tid='");
2323 Xml.Append(XML.Encode(TransactionId));
2324 }
2325
2326 if (!string.IsNullOrEmpty(SuccessUrl))
2327 {
2328 Xml.Append("' successUrl='");
2329 Xml.Append(XML.Encode(SuccessUrl));
2330 }
2331
2332 if (!string.IsNullOrEmpty(FailureUrl))
2333 {
2334 Xml.Append("' failureUrl='");
2335 Xml.Append(XML.Encode(FailureUrl));
2336 }
2337
2338 if (!string.IsNullOrEmpty(CancelUrl))
2339 {
2340 Xml.Append("' cancelUrl='");
2341 Xml.Append(XML.Encode(CancelUrl));
2342 }
2343
2344 Xml.Append("'/>");
2345
2346 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
2347 {
2348 TransactionId = null;
2349 XmlElement E;
2350
2351 if (e.Ok &&
2352 !((E = e.FirstElement) is null) &&
2353 E.LocalName == "transaction" &&
2354 E.NamespaceURI == NamespaceEDaler)
2355 {
2356 TransactionId = XML.Attribute(E, "tid");
2357 }
2358 else
2359 e.Ok = false;
2360
2361 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
2362
2363 }, State);
2364 }
2365
2376 public Task<string> InitiateSellEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
2377 {
2378 return this.InitiateSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency);
2379 }
2380
2391 public Task<string> InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2392 decimal Amount, string Currency)
2393 {
2394 return this.InitiateSellEDalerAsync(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null);
2395 }
2396
2410 public Task<string> InitiateSellEDalerAsync(string ServiceId, string ServiceProvider,
2411 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2412 {
2413 return this.InitiateSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
2414 }
2415
2430 public async Task<string> InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2431 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2432 {
2433 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
2434
2435 await this.InitiateSellEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
2436 (Sender, e) =>
2437 {
2438 if (e.Ok)
2439 Result.TrySetResult(e.TransactionId);
2440 else
2441 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
2442
2443 return Task.CompletedTask;
2444 }, null);
2445
2446 return await Result.Task;
2447 }
2448
2449 private Task SellEDalerClientUrlEventHandler(object Sender, MessageEventArgs e)
2450 {
2451 string TransactionId = XML.Attribute(e.Content, "tid");
2452 string Url = XML.Attribute(e.Content, "url");
2453
2454 return this.SellEDalerClientUrlReceived.Raise(this, new SellEDalerClientUrlEventArgs(e, TransactionId, Url));
2455 }
2456
2462 public event EventHandlerAsync<SellEDalerClientUrlEventArgs> SellEDalerClientUrlReceived;
2463
2464 private Task SellEDalerCompletedEventHandler(object Sender, MessageEventArgs e)
2465 {
2466 string TransactionId = XML.Attribute(e.Content, "tid");
2467 string Currency = XML.Attribute(e.Content, "currency");
2468 decimal Amount = XML.Attribute(e.Content, "amount", 0M);
2469
2470 return this.SellEDalerCompleted.Raise(this, new PaymentCompletedEventArgs(e, TransactionId, Amount, Currency));
2471 }
2472
2477 public event EventHandlerAsync<PaymentCompletedEventArgs> SellEDalerCompleted;
2478
2479 private Task SellEDalerErrorEventHandler(object Sender, MessageEventArgs e)
2480 {
2481 string TransactionId = XML.Attribute(e.Content, "tid");
2482 string Error = e.Content.InnerText;
2483
2484 return this.SellEDalerError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
2485 }
2486
2491 public event EventHandlerAsync<PaymentErrorEventArgs> SellEDalerError;
2492
2493 #endregion
2494
2495 }
2496}
Account event
Definition: AccountEvent.cs:16
Guid TransactionId
Transaction ID
Definition: AccountEvent.cs:38
Contains information about a balance.
Definition: Balance.cs:11
CaseInsensitiveString Currency
Currency of amount.
Definition: Balance.cs:54
AccountEvent Event
Any account event associated to the balance message.
Definition: Balance.cs:59
decimal Amount
Amount at given point in time.
Definition: Balance.cs:44
DateTime Timestamp
Timestamp of balance.
Definition: Balance.cs:39
Balance(DateTime Timestamp, decimal Amount, decimal Reserved, CaseInsensitiveString Currency, AccountEvent Event)
Contains information about a balance.
Definition: Balance.cs:26
eDaler XMPP client.
Definition: EDalerClient.cs:23
override string[] Extensions
Implemented extensions.
Definition: EDalerClient.cs:93
Task InitiateSellEDaler(string ServiceId, string ServiceProvider, decimal Amount, string Currency, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for selling eDaler.
Task GetAccountEvents(int MaxEvents, DateTime From, EventHandlerAsync< AccountEventsEventArgs > Callback, object State)
Gets account events associated with the wallet of the account.
EDalerClient(XmppClient Client, ContractsClient ContractsClient, string ComponentAddress)
eDaler XMPP client.
Definition: EDalerClient.cs:42
Task GetBalance(string ComponentAddress, EventHandlerAsync< BalanceIqResultEventArgs > Callback, object State)
Gets the current balance of the eDaler wallet associated with the account.
Task GetServiceProvidersForSellingEDaler(string ComponentAddress, EventHandlerAsync< SellEDalerServiceProvidersEventArgs > Callback, object State)
Gets available service providers who can help the user sell eDaler.
EventHandlerAsync< PaymentErrorEventArgs > BuyEDalerOptionsError
Event raised when a process of getting payment options for buying eDaler, initiated using a call to I...
Task< string > InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for buying eDaler.
Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for selling eDaler.
async Task< string > InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for buying eDaler.
string CreateIncompletePayMeUri(LegalIdentity Id, decimal? Amount, decimal? AmountExtra, string Currency, string PrivateMessage)
Generates an incomplete eDaler PayMe URI.
Task GetBalance(EventHandlerAsync< BalanceIqResultEventArgs > Callback, object State)
Gets the current balance of the eDaler wallet associated with the account.
async Task< ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync(string ComponentAddress)
Gets available service providers who can help the user sell eDaler.
Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for selling eDaler.
Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents)
Gets account events associated with the wallet of the account.
async Task< string > CreateFullPaymentUri(LegalIdentity RecipientLegalId, decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays, string PrivateMessage)
Creates a full payment URI.
Task< string > InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for getting payment options for buying eDaler.
Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents, DateTime From)
Gets account events associated with the wallet of the account.
const string NamespaceEDaler
Namespace of eDaler component.
Definition: EDalerClient.cs:27
Task< Balance > GetBalanceAsync()
Gets the current balance of the eDaler wallet associated with the account.
Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for selling eDaler.
override void Dispose()
IDisposable.Dispose
Definition: EDalerClient.cs:66
async Task< Transaction > SendEDalerUriAsync(string ComponentAddress, string Uri)
Sends an eDaler URI to the server
async Task< string > DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId, string RemoteEndPoint, bool LocalIsRecipient)
Decrypts a message that was aimed at the client using the current keys.
async Task< string > CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays, string Message)
Creates a full payment URI.
Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents)
Gets account events associated with the wallet of the account.
EventHandlerAsync< SellEDalerClientUrlEventArgs > SellEDalerOptionsClientUrlReceived
Event raised when a Client URL has been sent to the client as part of a process of getting payment op...
string DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId, bool LocalIsRecipient)
Decrypts a message that was aimed at the client using the current keys.
EventHandlerAsync< PaymentErrorEventArgs > SellEDalerOptionsError
Event raised when a process of getting payment options for selling eDaler, initiated using a call to ...
string CreateIncompletePayMeUri(string BareJid, decimal? Amount, decimal? AmountExtra, string Currency, string Message)
Generates an incomplete eDaler PayMe URI.
EventHandlerAsync< PaymentErrorEventArgs > BuyEDalerError
Event raised when a process of buying eDaler, initiated using a call to InitiateBuyEDalerAsync,...
Task GetServiceProvidersForBuyingEDaler(string ComponentAddress, EventHandlerAsync< BuyEDalerServiceProvidersEventArgs > Callback, object State)
Gets available service providers who can help the user buy eDaler.
Task< string > CreateFullPaymentUri(LegalIdentity ToLegalId, decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
Creates a full payment URI.
async Task< string > InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for selling eDaler.
Task GetServiceProvidersForBuyingEDaler(EventHandlerAsync< BuyEDalerServiceProvidersEventArgs > Callback, object State)
Gets available service providers who can help the user buy eDaler.
async Task<(decimal, string, PendingPayment[])> GetPendingPayments()
Gets the amount of payments pending to be processed.
Task< string > InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for buying eDaler.
Task< Transaction > SendEDalerUriAsync(string Uri)
Sends an eDaler URI to the server
async Task< string > InitiateGetOptionsSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for getting payment options for selling eDaler.
Task SendEDalerUri(string ComponentAddress, string Uri, EventHandlerAsync< TransactionEventArgs > Callback, object State)
Sends an eDaler URI to the server
Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for selling eDaler.
EventHandlerAsync< PaymentOptionsEventArgs > BuyEDalerOptionsCompleted
Event raised when a process of getting payment options for buying eDaler, initiated using a call to I...
EventHandlerAsync< PaymentErrorEventArgs > SellEDalerError
Event raised when a process of selling eDaler, initiated using a call to InitiateSellEDalerAsync,...
Task< string > InitiateSellEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for selling eDaler.
Task InitiateBuyEDaler(string ServiceId, string ServiceProvider, decimal Amount, string Currency, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for buying eDaler.
Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for buying eDaler.
Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for buying eDaler.
async Task< Balance > GetBalanceAsync(string ComponentAddress)
Gets the current balance of the eDaler wallet associated with the account.
Task< string > CreateFullPaymentUri(decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
Creates a full payment URI to anyone who is the first in claiming the URI.
Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for selling eDaler.
EventHandlerAsync< PaymentOptionsEventArgs > SellEDalerOptionsCompleted
Event raised when a process of getting payment options for selling eDaler, initiated using a call to ...
EventHandlerAsync< BuyEDalerClientUrlEventArgs > BuyEDalerOptionsClientUrlReceived
Event raised when a Client URL has been sent to the client as part of a process of getting payment op...
Task InitiateSellEDaler(string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for selling eDaler.
EventHandlerAsync< PaymentCompletedEventArgs > BuyEDalerCompleted
Event raised when a process of buying eDaler, initiated using a call to InitiateBuyEDalerAsync,...
Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for buying eDaler.
EventHandlerAsync< PaymentCompletedEventArgs > SellEDalerCompleted
Event raised when a process of selling eDaler, initiated using a call to InitiateSellEDalerAsync,...
Task< IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
Gets available service providers who can help the user buy eDaler.
Task< ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
Gets available service providers who can help the user sell eDaler.
Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for selling eDaler.
EventHandlerAsync< SellEDalerClientUrlEventArgs > SellEDalerClientUrlReceived
Event raised when a Client URL has been sent to the client as part of a process of selling eDaler sta...
EventHandlerAsync< BuyEDalerClientUrlEventArgs > BuyEDalerClientUrlReceived
Event raised when a Client URL has been sent to the client as part of a process of buying eDaler star...
Task GetAccountEvents(string ComponentAddress, int MaxEvents, EventHandlerAsync< AccountEventsEventArgs > Callback, object State)
Gets account events associated with the wallet of the account.
Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for buying eDaler.
Task GetAccountEvents(int MaxEvents, EventHandlerAsync< AccountEventsEventArgs > Callback, object State)
Gets account events associated with the wallet of the account.
async Task< string > InitiateGetOptionsBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for getting payment options for buying eDaler.
Task GetServiceProvidersForSellingEDaler(EventHandlerAsync< SellEDalerServiceProvidersEventArgs > Callback, object State)
Gets available service providers who can help the user sell eDaler.
string ComponentAddress
Address of eDaler component
Definition: EDalerClient.cs:88
Task SendEDalerUri(string Uri, EventHandlerAsync< TransactionEventArgs > Callback, object State)
Sends an eDaler URI to the server
Task< string > InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider)
Initiates a process for getting payment options for selling eDaler.
EventHandlerAsync< BalanceEventArgs > BalanceUpdated
Event raised when the client receives notification that the balance has been updated.
Task InitiateBuyEDaler(string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for buying eDaler.
async Task< IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync(string ComponentAddress)
Gets available service providers who can help the user buy eDaler.
Task< string > CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
Creates a full payment URI.
Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for buying eDaler.
Task< string > InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider)
Initiates a process for getting payment options for buying eDaler.
Task< string > InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for buying eDaler.
async Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents, DateTime From)
Gets account events associated with the wallet of the account.
Task GetAccountEvents(string ComponentAddress, int MaxEvents, DateTime From, EventHandlerAsync< AccountEventsEventArgs > Callback, object State)
Gets account events associated with the wallet of the account.
Task< string > InitiateSellEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for selling eDaler.
Task< string > InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for selling eDaler.
Task< string > InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
Initiates a process for getting payment options for selling eDaler.
Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider, EventHandlerAsync< TransactionIdEventArgs > Callback, object State)
Initiates a process for getting payment options for buying eDaler.
Account events event arguments.
Wallet balance event arguments.
Event arguments for events where a client URL needs to be displayed when buying eDaler.
Service Providers for buying eDaler event arguments.
Event arguments for event signalling the completion of a payment operation.
Event arguments for event signalling an error of a payment operation.
Event arguments for operations returning payment options.
Event arguments for events where a client URL needs to be displayed when selling eDaler.
Service Providers for selling eDaler event arguments.
Event arguments for operations returning a transaction object.
Event arguments for operations returning a transaction ID.
Information about last balance statement
Definition: LastBalance.cs:12
PendingPayment[] Pending
Pending payments
Definition: LastBalance.cs:56
DateTime Timestamp
Balance timestamp
Definition: LastBalance.cs:29
Contains information about a pending payment.
DateTime Expires
When payment expires
decimal Amount
Amount
Guid Id
ID of payment
CaseInsensitiveString Currency
Payment Currency
Represents a transaction in the eDaler network.
Definition: Transaction.cs:36
static Transaction FromXml(XmlElement Xml)
Parses inforation about a transaction from XML.
Definition: Transaction.cs:209
Helps with parsing of commong data types.
Definition: CommonTypes.cs:15
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:596
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:48
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:1062
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Definition: XML.cs:892
Class representing an event.
Definition: Event.cs:11
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
Adds support for legal identities, smart contracts and signatures to an XMPP client.
Contains information about a service provider.
Abstract base class of signatures
Definition: Signature.cs:10
Event arguments for message events.
string From
From where the message was received.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmlElement Content
Content of the message. For messages that are processed by registered message handlers,...
XmppException StanzaError
Any stanza error returned.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters a Message handler.
Definition: XmppClient.cs:2884
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers a Message handler.
Definition: XmppClient.cs:2852
Task< uint > SendIqSet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Set request.
Definition: XmppClient.cs:3646
Task< uint > SendIqGet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Get request.
Definition: XmppClient.cs:3598
Base class for XMPP Extensions.
XmppClient client
XMPP Client used by the extension.
void Exception(Exception Exception)
Called to inform the viewer of an exception state.
XmppClient Client
XMPP Client.
Represents a case-insensitive string.
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
Static class managing persistent settings.
static async Task< string > GetAsync(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Class managing a script expression.
Definition: Expression.cs:41
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
Definition: Expression.cs:4461
Collection of variables.
Definition: Variables.cs:25
Interface for information about a service provider.
SignWith
Options on what keys to use when signing data.
Definition: Enumerations.cs:82
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:14
static bool TryParse(string s, out Duration Result)
Tries to parse a duration value.
Definition: Duration.cs:86