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;
3using System.Collections.Generic;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
7using Waher.Content;
9using Waher.Events;
16using Waher.Script;
17
18namespace EDaler
19{
24 {
28 public const string NamespaceEDaler = "http://waher.se/Schema/eDaler.xsd";
29
30 internal const string EDalerBalanceKeyPrefix = "EDaler.Balance.";
31 internal const string EDalerRemoteKeyPrefix = "EDaler.Remote.Key.";
32
33 private readonly ContractsClient contractsClient;
34 private readonly string componentAddress;
35 private LastBalance balance = null;
36
44 : base(Client)
45 {
46 this.componentAddress = ComponentAddress;
47 this.contractsClient = ContractsClient;
48
49 Client.RegisterMessageHandler("balance", NamespaceEDaler, this.BalanceEventHandler, true);
50 Client.RegisterMessageHandler("buyEDalerOptionsClientUrl", NamespaceEDaler, this.BuyEDalerOptionsClientUrlEventHandler, false);
51 Client.RegisterMessageHandler("buyEDalerOptionsCompleted", NamespaceEDaler, this.BuyEDalerOptionsCompletedEventHandler, false);
52 Client.RegisterMessageHandler("buyEDalerOptionsError", NamespaceEDaler, this.BuyEDalerOptionsErrorEventHandler, false);
53 Client.RegisterMessageHandler("buyEDalerClientUrl", NamespaceEDaler, this.BuyEDalerClientUrlEventHandler, false);
54 Client.RegisterMessageHandler("buyEDalerCompleted", NamespaceEDaler, this.BuyEDalerCompletedEventHandler, false);
55 Client.RegisterMessageHandler("buyEDalerError", NamespaceEDaler, this.BuyEDalerErrorEventHandler, false);
56 Client.RegisterMessageHandler("sellEDalerOptionsClientUrl", NamespaceEDaler, this.SellEDalerOptionsClientUrlEventHandler, false);
57 Client.RegisterMessageHandler("sellEDalerOptionsCompleted", NamespaceEDaler, this.SellEDalerOptionsCompletedEventHandler, false);
58 Client.RegisterMessageHandler("sellEDalerOptionsError", NamespaceEDaler, this.SellEDalerOptionsErrorEventHandler, false);
59 Client.RegisterMessageHandler("sellEDalerClientUrl", NamespaceEDaler, this.SellEDalerClientUrlEventHandler, false);
60 Client.RegisterMessageHandler("sellEDalerCompleted", NamespaceEDaler, this.SellEDalerCompletedEventHandler, false);
61 Client.RegisterMessageHandler("sellEDalerError", NamespaceEDaler, this.SellEDalerErrorEventHandler, false);
62 }
63
67 public override void Dispose()
68 {
69 this.client.UnregisterMessageHandler("balance", NamespaceEDaler, this.BalanceEventHandler, true);
70 this.client.UnregisterMessageHandler("buyEDalerOptionsClientUrl", NamespaceEDaler, this.BuyEDalerOptionsClientUrlEventHandler, false);
71 this.client.UnregisterMessageHandler("buyEDalerOptionsCompleted", NamespaceEDaler, this.BuyEDalerOptionsCompletedEventHandler, false);
72 this.client.UnregisterMessageHandler("buyEDalerOptionsError", NamespaceEDaler, this.BuyEDalerOptionsErrorEventHandler, false);
73 this.client.UnregisterMessageHandler("buyEDalerClientUrl", NamespaceEDaler, this.BuyEDalerClientUrlEventHandler, false);
74 this.client.UnregisterMessageHandler("buyEDalerCompleted", NamespaceEDaler, this.BuyEDalerCompletedEventHandler, false);
75 this.client.UnregisterMessageHandler("buyEDalerError", NamespaceEDaler, this.BuyEDalerErrorEventHandler, false);
76 this.client.UnregisterMessageHandler("sellEDalerOptionsClientUrl", NamespaceEDaler, this.SellEDalerOptionsClientUrlEventHandler, false);
77 this.client.UnregisterMessageHandler("sellEDalerOptionsCompleted", NamespaceEDaler, this.SellEDalerOptionsCompletedEventHandler, false);
78 this.client.UnregisterMessageHandler("sellEDalerOptionsError", NamespaceEDaler, this.SellEDalerOptionsErrorEventHandler, false);
79 this.client.UnregisterMessageHandler("sellEDalerClientUrl", NamespaceEDaler, this.SellEDalerClientUrlEventHandler, false);
80 this.client.UnregisterMessageHandler("sellEDalerCompleted", NamespaceEDaler, this.SellEDalerCompletedEventHandler, false);
81 this.client.UnregisterMessageHandler("sellEDalerError", NamespaceEDaler, this.SellEDalerErrorEventHandler, false);
82
83 base.Dispose();
84 }
85
89 public string ComponentAddress => this.componentAddress;
90
94 public override string[] Extensions => new string[] { };
95
96 #region Balance
97
103 public Task GetBalance(EventHandlerAsync<BalanceIqResultEventArgs> Callback, object State)
104 {
105 return this.GetBalance(this.componentAddress, Callback, State);
106 }
107
114 public Task GetBalance(string ComponentAddress, EventHandlerAsync<BalanceIqResultEventArgs> Callback, object State)
115 {
116 StringBuilder Xml = new StringBuilder();
117
118 Xml.Append("<balance xmlns='");
119 Xml.Append(NamespaceEDaler);
120 Xml.Append("'/>");
121
122 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
123 {
124 XmlElement E;
126
127 if (e.Ok &&
128 !((E = e.FirstElement) is null) &&
129 E.LocalName == "balance" &&
130 E.NamespaceURI == NamespaceEDaler)
131 {
132 Balance = await this.ParseBalance(E);
133
134 if (Balance is null)
135 e.Ok = false;
136 else
137 await this.BalanceReported(Balance);
138 }
139 else
140 {
141 e.Ok = false;
142 Balance = null;
143 }
144
145 await Callback.Raise(this, new BalanceIqResultEventArgs(e, Balance));
146
147 }, State);
148 }
149
150 private async Task BalanceReported(Balance Balance)
151 {
152 string LastBalanceKey = EDalerBalanceKeyPrefix + this.client.BareJID;
153 if (this.balance is null)
154 this.balance = await RuntimeSettings.GetAsync(LastBalanceKey, (object)null) as LastBalance;
155
156 bool Changed = false;
157
158 if (this.balance is null ||
159 this.balance.Timestamp < Balance.Timestamp ||
160 (this.balance.Timestamp < Balance.Timestamp.AddSeconds(1) && this.balance.Balance != Balance.Amount))
161 {
162 if (this.balance is null)
163 {
164 this.balance = new LastBalance()
165 {
167 Currency = Balance.Currency,
168 Timestamp = Balance.Timestamp
169 };
170 }
171 else
172 {
173 this.balance.Balance = Balance.Amount;
174 this.balance.Currency = Balance.Currency;
175 this.balance.Timestamp = Balance.Timestamp;
176 }
177
178 Changed = true;
179 }
180
181 if (!(this.balance.Pending is null) && !(Balance.Event is null))
182 {
183 List<PendingPayment> Pending = new List<PendingPayment>();
184 DateTime Today = DateTime.Today;
185
186 foreach (PendingPayment Payment in this.balance.Pending)
187 {
188 if (Payment.Expires.AddDays(1) < Today || Payment.Id == Balance.Event.TransactionId)
189 {
190 Changed = true;
191 continue;
192 }
193
194 Pending.Add(Payment);
195 }
196
197 if (Changed)
198 this.balance.Pending = Pending.ToArray();
199 }
200
201 if (Changed)
202 await RuntimeSettings.SetAsync(LastBalanceKey, this.balance);
203 }
204
209 public Task<Balance> GetBalanceAsync()
210 {
211 return this.GetBalanceAsync(this.componentAddress);
212 }
213
219 public async Task<Balance> GetBalanceAsync(string ComponentAddress)
220 {
221 TaskCompletionSource<Balance> Result = new TaskCompletionSource<Balance>();
222
223 await this.GetBalance(ComponentAddress, async (Sender, e) =>
224 {
225 if (e.Ok)
226 {
227 await this.BalanceReported(e.Balance);
228 Result.TrySetResult(e.Balance);
229 }
230 else
231 Result.TrySetException(e.StanzaError ?? new Exception("Unable to get current balance."));
232
233 }, null);
234
235 return await Result.Task;
236 }
237
238 private async Task BalanceEventHandler(object Sender, MessageEventArgs e)
239 {
240 if (e.From != this.componentAddress)
241 return;
242
243 Balance Balance = await this.ParseBalance(e.Content);
244 await this.BalanceReported(Balance);
245
246 await this.BalanceUpdated.Raise(this, new BalanceEventArgs(Balance));
247 }
248
249 private async Task<Balance> ParseBalance(XmlElement Xml)
250 {
251 CaseInsensitiveString Currency = null;
252 DateTime? Timestamp = null;
253 decimal? Balance = null;
254 decimal Reserved = 0;
255 AccountEvent Event = null;
256
257 foreach (XmlAttribute Attr in Xml.Attributes)
258 {
259 switch (Attr.Name)
260 {
261 case "amount":
262 if (!CommonTypes.TryParse(Attr.Value, out decimal d))
263 return null;
264
265 Balance = d;
266 break;
267
268 case "reserved":
269 if (!CommonTypes.TryParse(Attr.Value, out d))
270 return null;
271
272 Reserved = d;
273 break;
274
275 case "currency":
276 Currency = Attr.Value;
277 break;
278
279 case "timestamp":
280 if (!XML.TryParse(Attr.Value, out DateTime TP))
281 return null;
282
283 Timestamp = TP;
284 break;
285 }
286 }
287
288 if (!Balance.HasValue || Currency is null || !Timestamp.HasValue)
289 return null;
290
291 foreach (XmlNode N in Xml.ChildNodes)
292 {
293 if (N is XmlElement E && E.LocalName == "event" && E.NamespaceURI == NamespaceEDaler)
294 {
295 Event = await AccountEvent.FromXml(E, this);
296 break;
297 }
298 }
299
300 return new Balance(Timestamp.Value, Balance.Value, Reserved, Currency, Event);
301 }
302
307 public event EventHandlerAsync<BalanceEventArgs> BalanceUpdated = null;
308
309 #endregion
310
311 #region eDaler URIs
312
319 public Task SendEDalerUri(string Uri, EventHandlerAsync<TransactionEventArgs> Callback, object State)
320 {
321 return this.SendEDalerUri(this.componentAddress, Uri, Callback, State);
322 }
323
331 public Task SendEDalerUri(string ComponentAddress, string Uri, EventHandlerAsync<TransactionEventArgs> Callback, object State)
332 {
333 StringBuilder Xml = new StringBuilder();
334
335 Xml.Append("<uri xmlns=\"");
336 Xml.Append(NamespaceEDaler);
337 Xml.Append("\">");
338 Xml.Append(XML.Encode(Uri));
339 Xml.Append("</uri>");
340
341 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
342 {
343 if (Callback is null)
344 return;
345
347
348 if (e.Ok)
349 {
350 if (e.FirstElement is null ||
351 e.FirstElement.LocalName != "tr" ||
352 e.FirstElement.NamespaceURI != NamespaceEDaler)
353 {
354 e.Ok = false;
355 }
356 else
357 Transaction = Transaction.FromXml(e.FirstElement);
358 }
359
360 await Callback.Raise(this, new TransactionEventArgs(e, Transaction));
361
362 }, State);
363 }
364
369 public Task<Transaction> SendEDalerUriAsync(string Uri)
370 {
371 return this.SendEDalerUriAsync(this.componentAddress, Uri);
372 }
373
379 public async Task<Transaction> SendEDalerUriAsync(string ComponentAddress, string Uri)
380 {
381 TaskCompletionSource<Transaction> Result = new TaskCompletionSource<Transaction>();
382
383 await this.SendEDalerUri(ComponentAddress, Uri, (Sender, e) =>
384 {
385 if (e.Ok)
386 Result.TrySetResult(e.Transaction);
387 else if (!(e.StanzaError is null))
388 Result.TrySetException(e.StanzaError);
389 else
390 Result.TrySetException(new Exception("Unable to process eDaler URI."));
391
392 return Task.CompletedTask;
393 }, null);
394
395 return await Result.Task;
396 }
397
398 #endregion
399
400 #region eDaler Account events
401
408 public Task GetAccountEvents(int MaxEvents, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
409 {
410 return this.GetAccountEvents(this.componentAddress, MaxEvents, DateTime.MaxValue, Callback, State);
411 }
412
420 public Task GetAccountEvents(string ComponentAddress, int MaxEvents, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
421 {
422 return this.GetAccountEvents(ComponentAddress, MaxEvents, DateTime.MaxValue, Callback, State);
423 }
424
432 public Task GetAccountEvents(int MaxEvents, DateTime From, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
433 {
434 return this.GetAccountEvents(this.componentAddress, MaxEvents, From, Callback, State);
435 }
436
445 public Task GetAccountEvents(string ComponentAddress, int MaxEvents, DateTime From, EventHandlerAsync<AccountEventsEventArgs> Callback, object State)
446 {
447 StringBuilder Xml = new StringBuilder();
448
449 Xml.Append("<events xmlns=\"");
450 Xml.Append(NamespaceEDaler);
451 Xml.Append("\" maxCount=\"");
452 Xml.Append(MaxEvents.ToString());
453
454 if (From != DateTime.MaxValue)
455 {
456 Xml.Append("\" from=\"");
457 Xml.Append(XML.Encode(From));
458 }
459
460 Xml.Append("\"/>");
461
462 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
463 {
464 List<AccountEvent> Events = new List<AccountEvent>();
465 bool More = false;
466
467 if (e.Ok)
468 {
469 if (e.FirstElement is null ||
470 e.FirstElement.LocalName != "events" ||
471 e.FirstElement.NamespaceURI != NamespaceEDaler)
472 {
473 e.Ok = false;
474 }
475 else
476 {
477 foreach (XmlNode N in e.FirstElement.ChildNodes)
478 {
479 if (!(N is XmlElement E) || E.NamespaceURI != NamespaceEDaler)
480 continue;
481
482 switch (E.LocalName)
483 {
484 case "event":
485 AccountEvent Event = await AccountEvent.FromXml(E, this);
486 Events.Add(Event);
487 break;
488
489 case "more":
490 More = true;
491 break;
492 }
493 }
494
495 await Callback.Raise(this, new AccountEventsEventArgs(Events.ToArray(), More, e));
496 }
497 }
498 }, State);
499 }
500
501
507 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents)
508 {
509 return this.GetAccountEventsAsync(this.componentAddress, MaxEvents, DateTime.MaxValue);
510 }
511
518 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents)
519 {
520 return this.GetAccountEventsAsync(ComponentAddress, MaxEvents, DateTime.MaxValue);
521 }
522
529 public Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents, DateTime From)
530 {
531 return this.GetAccountEventsAsync(this.componentAddress, MaxEvents, From);
532 }
533
541 public async Task<(AccountEvent[], bool)> GetAccountEventsAsync(string ComponentAddress, int MaxEvents, DateTime From)
542 {
543 TaskCompletionSource<(AccountEvent[], bool)> Result = new TaskCompletionSource<(AccountEvent[], bool)>();
544
545 await this.GetAccountEvents(ComponentAddress, MaxEvents, From, async (Sender, e) =>
546 {
547 if (e.Ok)
548 {
549 try
550 {
551 if (this.balance is null)
552 await this.GetBalanceAsync();
553
554 if (!(this.balance.Pending is null) && this.balance.Pending.Length > 0)
555 {
556 Dictionary<Guid, PendingPayment> Pending = new Dictionary<Guid, PendingPayment>();
557 DateTime Today = DateTime.Today;
558 bool Changed = false;
559
560 foreach (PendingPayment Payment in this.balance.Pending)
561 {
562 if (Payment.Expires.AddDays(1) < Today)
563 Changed = true;
564 else
565 Pending[Payment.Id] = Payment;
566 }
567
568 foreach (AccountEvent Event in e.Events)
569 {
570 if (Pending.Remove(Event.TransactionId))
571 Changed = true;
572 }
573
574 if (Changed)
575 {
576 PendingPayment[] Pending2 = new PendingPayment[Pending.Count];
577 Pending.Values.CopyTo(Pending2, 0);
578 this.balance.Pending = Pending2;
579
580 await RuntimeSettings.SetAsync(EDalerBalanceKeyPrefix + this.client.BareJID, this.balance);
581 }
582 }
583
584 Result.TrySetResult((e.Events, e.More));
585 }
586 catch (Exception ex)
587 {
588 Result.TrySetException(ex);
589 }
590 }
591 else if (!(e.StanzaError is null))
592 Result.TrySetException(e.StanzaError);
593 else
594 Result.TrySetException(new Exception("Unable to process eDaler URI."));
595
596 }, null);
597
598 return await Result.Task;
599 }
600
601 #endregion
602
603 #region Payment URIs
604
613 public Task<string> CreateFullPaymentUri(decimal Amount, decimal? AmountExtra,
614 CaseInsensitiveString Currency, int ValidNrDays)
615 {
616 return this.CreateFullPaymentUri(string.Empty, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
617 }
618
628 public Task<string> CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra,
629 CaseInsensitiveString Currency, int ValidNrDays)
630 {
631 return this.CreateFullPaymentUri(ToBareJid, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
632 }
633
644 public async Task<string> CreateFullPaymentUri(string ToBareJid, decimal Amount, decimal? AmountExtra,
645 CaseInsensitiveString Currency, int ValidNrDays, string Message)
646 {
647 await this.ValidatePaymentArguments(Amount, AmountExtra, Currency, ValidNrDays);
648
649 StringBuilder Uri = new StringBuilder();
650 DateTime Created = DateTime.UtcNow;
651 DateTime Expires = DateTime.Today.AddDays(ValidNrDays);
652 Guid Id = Guid.NewGuid();
653
654 Uri.Append("edaler:id=");
655 Uri.Append(Id.ToString());
656 Uri.Append(";f=");
657 Uri.Append(XML.Encode(this.client.BareJID));
658
659 if (!string.IsNullOrEmpty(ToBareJid))
660 {
661 if (ToBareJid.IndexOf('@') < 0)
662 {
663 Uri.Append(";xx="); // Destruction (payment to operator)
664 Uri.Append(XML.Encode(ToBareJid));
665 }
666 else
667 {
668 Uri.Append(";t=");
669 Uri.Append(XML.Encode(ToBareJid));
670 }
671 }
672
673 Uri.Append(";am=");
674 Uri.Append(CommonTypes.Encode(Amount));
675
676 if (AmountExtra.HasValue)
677 {
678 Uri.Append(";amx=");
679 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
680 }
681
682 Uri.Append(";cu=");
683 Uri.Append(XML.Encode(Currency));
684 Uri.Append(";cr=");
685 Uri.Append(XML.Encode(Created, false));
686 Uri.Append(";ex=");
687 Uri.Append(XML.Encode(Expires, true));
688
689 if (!string.IsNullOrEmpty(Message))
690 {
691 Uri.Append(";m=");
692 Uri.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(Message)));
693 }
694
695 await this.SignAndCheckBalance(Uri, Amount, AmountExtra, Currency, Id, Expires, ToBareJid);
696
697 return Uri.ToString();
698 }
699
700 private async Task ValidatePaymentArguments(decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
701 {
702 if (ValidNrDays <= 0)
703 throw new ArgumentException("Must be a positive integer.", nameof(ValidNrDays));
704
705 if (Amount <= 0)
706 throw new ArgumentException("Amount must be positive.", nameof(Amount));
707
708 if (AmountExtra.HasValue && AmountExtra.Value <= 0)
709 throw new ArgumentException("Amount must be positive.", nameof(AmountExtra));
710
711 if (this.balance is null)
712 await this.GetBalanceAsync();
713
714 LastBalance Balance = this.balance;
715 if (Currency != Balance.Currency) // TODO: Currency conversion, if supported by neuron
716 throw new ArgumentException("Currency does not correspond to currency of wallet.", nameof(Currency));
717 }
718
719 private async Task SignAndCheckBalance(StringBuilder Uri, decimal Amount, decimal? AmountExtra, string Currency,
720 Guid Id, DateTime Expires, string To)
721 {
722 byte[] PreSign = Encoding.UTF8.GetBytes(Uri.ToString());
723 byte[] Signature = await this.contractsClient.SignAsync(PreSign, SignWith.LatestApprovedId);
724
725 Uri.Append(";s=");
726 Uri.Append(Convert.ToBase64String(Signature));
727
729 DateTime Today = DateTime.Today;
730 List<PendingPayment> Pending;
731 decimal PendingAmount;
732
733 do
734 {
735 Balance = this.balance;
736 Pending = new List<PendingPayment>();
737 PendingAmount = 0;
738
739 if (!(Balance.Pending is null))
740 {
741 foreach (PendingPayment PendingPayment in Balance.Pending)
742 {
743 if (PendingPayment.Expires.AddDays(1) >= Today)
744 {
745 Pending.Add(PendingPayment);
746 PendingAmount += PendingPayment.Amount;
747 }
748 }
749 }
750
751 if (Amount + (AmountExtra ?? 0) + PendingAmount > Balance.Balance)
752 {
753 StringBuilder Msg = new StringBuilder();
754
755 Msg.Append("Amount larger than current balance. Amount: ");
756 Msg.Append(Amount.ToString());
757
758 if (AmountExtra.HasValue)
759 {
760 Msg.Append(". Extra: ");
761 Msg.Append(AmountExtra.Value.ToString());
762 }
763
764 if (PendingAmount > 0)
765 {
766 Msg.Append(". Pending: ");
767 Msg.Append(PendingAmount.ToString());
768 }
769
770 Msg.Append(". Balance: ");
771 Msg.Append(Balance.Balance.ToString());
772
773 Msg.Append(". Difference: ");
774 Msg.Append((Balance.Balance - Amount - (AmountExtra ?? 0) - PendingAmount).ToString());
775
776 throw new InvalidOperationException(Msg.ToString());
777 }
778
779 Pending.Add(new PendingPayment()
780 {
781 Id = Id,
782 Expires = Expires,
783 Currency = Currency,
784 Amount = Amount + (AmountExtra ?? 0),
785 From = this.client.BareJID,
786 To = To,
787 Uri = Uri.ToString()
788 });
789
790 Balance.Pending = Pending.ToArray();
791
792 await RuntimeSettings.SetAsync(EDalerBalanceKeyPrefix + this.client.BareJID, Balance);
793 }
794 while (this.balance != Balance);
795 }
796
806 public Task<string> CreateFullPaymentUri(LegalIdentity ToLegalId, decimal Amount, decimal? AmountExtra,
807 CaseInsensitiveString Currency, int ValidNrDays)
808 {
809 return this.CreateFullPaymentUri(ToLegalId, Amount, AmountExtra, Currency, ValidNrDays, string.Empty);
810 }
811
823 public async Task<string> CreateFullPaymentUri(LegalIdentity ToLegalId, decimal Amount, decimal? AmountExtra,
824 CaseInsensitiveString Currency, int ValidNrDays, string PrivateMessage)
825 {
826 if (ToLegalId is null)
827 throw new ArgumentNullException("Legal ID cannot be null.", nameof(ToLegalId));
828
829 if (!ToLegalId.HasClientPublicKey)
830 throw new ArgumentNullException("Legal ID lacks a public key.", nameof(ToLegalId));
831
832 await this.ValidatePaymentArguments(Amount, AmountExtra, Currency, ValidNrDays);
833
834 StringBuilder Uri = new StringBuilder();
835 DateTime Created = DateTime.UtcNow;
836 DateTime Expires = DateTime.Today.AddDays(ValidNrDays);
837 Guid Id = Guid.NewGuid();
838
839 byte[] MessageBin = Encoding.UTF8.GetBytes(PrivateMessage ?? string.Empty);
840 (byte[] EncryptedMessage, byte[] LocalPublicKey) = this.contractsClient.Encrypt(MessageBin, Id.ToByteArray(), ToLegalId.ClientPubKey, ToLegalId.ClientKeyName);
841
842 await RuntimeSettings.SetAsync(EDalerRemoteKeyPrefix + ToLegalId.Id, Convert.ToBase64String(ToLegalId.ClientPubKey));
843 string FromLegalId = await this.contractsClient.GetLatestApprovedLegalId(LocalPublicKey);
844
845 Uri.Append("edaler:id=");
846 Uri.Append(Id.ToString());
847
848 if (FromLegalId is null)
849 {
850 Uri.Append(";f=");
851 Uri.Append(XML.Encode(this.client.BareJID));
852 }
853 else
854 {
855 Uri.Append(";fi=");
856 Uri.Append(XML.Encode(FromLegalId));
857 }
858
859 Uri.Append(";ti=");
860 Uri.Append(XML.Encode(ToLegalId.Id));
861 Uri.Append(";am=");
862 Uri.Append(CommonTypes.Encode(Amount));
863
864 if (AmountExtra.HasValue)
865 {
866 Uri.Append(";amx=");
867 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
868 }
869
870 Uri.Append(";cu=");
871 Uri.Append(XML.Encode(Currency));
872 Uri.Append(";cr=");
873 Uri.Append(XML.Encode(Created, false));
874 Uri.Append(";ex=");
875 Uri.Append(XML.Encode(Expires, true));
876
877 if (!string.IsNullOrEmpty(PrivateMessage))
878 {
879 Uri.Append(";em=");
880 Uri.Append(Convert.ToBase64String(EncryptedMessage));
881 Uri.Append(";ep=");
882 Uri.Append(Convert.ToBase64String(LocalPublicKey));
883 }
884
885 await this.SignAndCheckBalance(Uri, Amount, AmountExtra, Currency, Id, Expires, ToLegalId.Id);
886
887 return Uri.ToString();
888 }
889
899 public string CreateIncompletePayMeUri(string BareJid, decimal? Amount, decimal? AmountExtra, string Currency, string Message)
900 {
901 return this.CreateIncompletePayMeUri(BareJid, "t", Amount, AmountExtra, Currency, Message);
902 }
903
915 public string CreateIncompletePayMeUri(LegalIdentity Id, decimal? Amount, decimal? AmountExtra,
916 string Currency, string PrivateMessage)
917 {
918 return this.CreateIncompletePayMeUri(Id.Id, "ti", Amount, AmountExtra, Currency, PrivateMessage);
919 }
920
921 private string CreateIncompletePayMeUri(string To, string ToType, decimal? Amount, decimal? AmountExtra,
922 string Currency, string Message)
923 {
924 StringBuilder Uri = new StringBuilder();
925
926 Uri.Append("edaler:cu=");
927 Uri.Append(Currency);
928
929 if (Amount.HasValue)
930 {
931 Uri.Append(";am=");
932 Uri.Append(CommonTypes.Encode(Amount.Value));
933 }
934
935 if (AmountExtra.HasValue)
936 {
937 Uri.Append(";amx=");
938 Uri.Append(CommonTypes.Encode(AmountExtra.Value));
939 }
940
941 Uri.Append(';');
942 Uri.Append(ToType);
943 Uri.Append('=');
944 Uri.Append(To);
945
946 if (!string.IsNullOrEmpty(Message))
947 {
948 Uri.Append(";m=");
949 Uri.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(Message)));
950 }
951
952 return Uri.ToString();
953 }
954
962 public async Task<string> DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId)
963 {
964 if (EncryptedMessage is null)
965 return string.Empty;
966
967 if (PublicKey is null)
968 return Encoding.UTF8.GetString(EncryptedMessage);
969
970 try
971 {
972 byte[] Decrypted;
973
974 if (PublicKey is null)
975 Decrypted = EncryptedMessage;
976 else
977 Decrypted = await this.contractsClient.Decrypt(EncryptedMessage, PublicKey, TransactionId.ToByteArray());
978
979 return Encoding.UTF8.GetString(Decrypted);
980 }
981 catch (Exception)
982 {
983 return string.Empty;
984 }
985 }
986
995 public async Task<string> DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId, string RemoteEndpoint)
996 {
997 if (!string.IsNullOrEmpty(RemoteEndpoint) && !(PublicKey is null))
998 {
999 string RemotePublicKey = await RuntimeSettings.GetAsync(EDalerRemoteKeyPrefix + RemoteEndpoint, string.Empty);
1000
1001 if (!string.IsNullOrEmpty(RemotePublicKey))
1002 {
1003 try
1004 {
1005 PublicKey = Convert.FromBase64String(RemotePublicKey);
1006 }
1007 catch (Exception ex)
1008 {
1009 Log.Exception(ex);
1010 }
1011 }
1012 }
1013
1014 return await this.DecryptMessage(EncryptedMessage, PublicKey, TransactionId);
1015 }
1016
1017 #endregion
1018
1019 #region Pending Payments
1020
1025 public async Task<(decimal, string, PendingPayment[])> GetPendingPayments()
1026 {
1027 if (this.balance is null)
1028 await this.GetBalanceAsync();
1029
1030 List<PendingPayment> PendingPayments = new List<PendingPayment>();
1031 DateTime Today = DateTime.Today;
1032 LastBalance Balance = this.balance;
1033 decimal PendingAmount = 0;
1034
1035 if (!(Balance.Pending is null))
1036 {
1037 foreach (PendingPayment PendingPayment in Balance.Pending)
1038 {
1039 if (PendingPayment.Expires.AddDays(1) >= Today)
1040 {
1041 PendingPayments.Add(new PendingPayment()
1042 {
1043 Id = PendingPayment.Id,
1044 Expires = PendingPayment.Expires,
1045 Currency = PendingPayment.Currency,
1046 Amount = PendingPayment.Amount,
1047 From = PendingPayment.From,
1048 To = PendingPayment.To,
1049 Uri = PendingPayment.Uri
1050 });
1051
1052 PendingAmount += PendingPayment.Amount;
1053 }
1054 }
1055 }
1056
1057 return (PendingAmount, Balance.Currency, PendingPayments.ToArray());
1058 }
1059
1060 #endregion
1061
1062 #region Service Providers for buying eDaler
1063
1069 public Task GetServiceProvidersForBuyingEDaler(EventHandlerAsync<BuyEDalerServiceProvidersEventArgs> Callback, object State)
1070 {
1071 return this.GetServiceProvidersForBuyingEDaler(this.componentAddress, Callback, State);
1072 }
1073
1080 public Task GetServiceProvidersForBuyingEDaler(string ComponentAddress,
1081 EventHandlerAsync<BuyEDalerServiceProvidersEventArgs> Callback, object State)
1082 {
1083 StringBuilder Xml = new StringBuilder();
1084
1085 Xml.Append("<buyEDalerProviders xmlns='");
1086 Xml.Append(NamespaceEDaler);
1087 Xml.Append("'/>");
1088
1089 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1090 {
1091 List<IBuyEDalerServiceProvider> Providers = null;
1092 XmlElement E;
1093
1094 if (e.Ok &&
1095 !((E = e.FirstElement) is null) &&
1096 E.LocalName == "providers" &&
1097 E.NamespaceURI == NamespaceEDaler)
1098 {
1099 Providers = new List<IBuyEDalerServiceProvider>();
1100
1101 foreach (XmlNode N in E.ChildNodes)
1102 {
1103 if (N is XmlElement E2 &&
1104 E2.LocalName == "provider" &&
1105 E2.NamespaceURI == NamespaceEDaler)
1106 {
1107 IBuyEDalerServiceProvider Provider = this.ParseServiceProvider<BuyEDalerServiceProvider>(E2);
1108
1109 if (!(Provider is null))
1110 Providers.Add(Provider);
1111 }
1112 }
1113 }
1114 else
1115 e.Ok = false;
1116
1117 await Callback.Raise(this, new BuyEDalerServiceProvidersEventArgs(e, Providers?.ToArray()));
1118
1119 }, State);
1120 }
1121
1122 private T ParseServiceProvider<T>(XmlElement Xml)
1123 where T : IServiceProviderWithTemplate, new()
1124 {
1125 string Id = null;
1126 string Type = null;
1127 string Name = null;
1128 string IconUrl = null;
1129 string TemplateId = null;
1130 int IconWidth = -1;
1131 int IconHeight = -1;
1132
1133 foreach (XmlAttribute Attr in Xml.Attributes)
1134 {
1135 switch (Attr.Name)
1136 {
1137 case "id":
1138 Id = Attr.Value;
1139 break;
1140
1141 case "type":
1142 Type = Attr.Value;
1143 break;
1144
1145 case "name":
1146 Name = Attr.Value;
1147 break;
1148
1149 case "iconUrl":
1150 IconUrl = Attr.Value;
1151 break;
1152
1153 case "iconWidth":
1154 if (!int.TryParse(Attr.Value, out int i))
1155 return default;
1156
1157 IconWidth = i;
1158 break;
1159
1160 case "iconHeight":
1161 if (!int.TryParse(Attr.Value, out i))
1162 return default;
1163
1164 IconHeight = i;
1165 break;
1166
1167 case "templateId":
1168 TemplateId = Attr.Value;
1169 break;
1170 }
1171 }
1172
1173 if (Id is null || Type is null || Name is null)
1174 return default;
1175
1176 if (string.IsNullOrEmpty(IconUrl))
1177 {
1178 T Temp = new T();
1179 return (T)Temp.Create(Id, Type, Name, TemplateId);
1180 }
1181 else
1182 {
1183 if (IconWidth < 0 || IconHeight < 0)
1184 return default;
1185
1186 T Temp = new T();
1187 return (T)Temp.Create(Id, Type, Name, IconUrl, IconWidth, IconHeight, TemplateId);
1188 }
1189 }
1190
1194 public Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
1195 {
1196 return this.GetServiceProvidersForBuyingEDalerAsync(this.componentAddress);
1197 }
1198
1203 public async Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync(string ComponentAddress)
1204 {
1205 TaskCompletionSource<IBuyEDalerServiceProvider[]> Providers = new TaskCompletionSource<IBuyEDalerServiceProvider[]>();
1206
1207 await this.GetServiceProvidersForBuyingEDaler(ComponentAddress, (Sender, e) =>
1208 {
1209 if (e.Ok)
1210 Providers.TrySetResult(e.ServiceProviders);
1211 else
1212 Providers.TrySetException(e.StanzaError ?? new Exception("Unable to get service providers."));
1213
1214 return Task.CompletedTask;
1215
1216 }, null);
1217
1218 return await Providers.Task;
1219 }
1220
1221 #endregion
1222
1223 #region Service Providers for selling eDaler
1224
1230 public Task GetServiceProvidersForSellingEDaler(EventHandlerAsync<SellEDalerServiceProvidersEventArgs> Callback, object State)
1231 {
1232 return this.GetServiceProvidersForSellingEDaler(this.componentAddress, Callback, State);
1233 }
1234
1241 public Task GetServiceProvidersForSellingEDaler(string ComponentAddress,
1242 EventHandlerAsync<SellEDalerServiceProvidersEventArgs> Callback, object State)
1243 {
1244 StringBuilder Xml = new StringBuilder();
1245
1246 Xml.Append("<sellEDalerProviders xmlns='");
1247 Xml.Append(NamespaceEDaler);
1248 Xml.Append("'/>");
1249
1250 return this.client.SendIqGet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1251 {
1252 List<ISellEDalerServiceProvider> Providers = null;
1253 XmlElement E;
1254
1255 if (e.Ok &&
1256 !((E = e.FirstElement) is null) &&
1257 E.LocalName == "providers" &&
1258 E.NamespaceURI == NamespaceEDaler)
1259 {
1260 Providers = new List<ISellEDalerServiceProvider>();
1261
1262 foreach (XmlNode N in E.ChildNodes)
1263 {
1264 if (N is XmlElement E2 &&
1265 E2.LocalName == "provider" &&
1266 E2.NamespaceURI == NamespaceEDaler)
1267 {
1268 ISellEDalerServiceProvider Provider = this.ParseServiceProvider<SellEDalerServiceProvider>(E2);
1269
1270 if (!(Provider is null))
1271 Providers.Add(Provider);
1272 }
1273 }
1274 }
1275 else
1276 e.Ok = false;
1277
1278 await Callback.Raise(this, new SellEDalerServiceProvidersEventArgs(e, Providers?.ToArray()));
1279
1280 }, State);
1281 }
1282
1286 public Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
1287 {
1288 return this.GetServiceProvidersForSellingEDalerAsync(this.componentAddress);
1289 }
1290
1295 public async Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync(string ComponentAddress)
1296 {
1297 TaskCompletionSource<ISellEDalerServiceProvider[]> Providers = new TaskCompletionSource<ISellEDalerServiceProvider[]>();
1298
1299 await this.GetServiceProvidersForSellingEDaler(ComponentAddress, (Sender, e) =>
1300 {
1301 if (e.Ok)
1302 Providers.TrySetResult(e.ServiceProviders);
1303 else
1304 Providers.TrySetException(e.StanzaError ?? new Exception("Unable to get service providers."));
1305
1306 return Task.CompletedTask;
1307
1308 }, null);
1309
1310 return await Providers.Task;
1311 }
1312
1313 #endregion
1314
1315 #region Initiation of getting Payment options for buying eDaler using smart contracts
1316
1324 public Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider,
1325 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1326 {
1327 return this.InitiateGetOptionsBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Callback, State);
1328 }
1329
1338 public Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1339 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1340 {
1341 return this.InitiateGetOptionsBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, null, null, null, null, Callback, State);
1342 }
1343
1355 public Task InitiateGetOptionsBuyEDaler(string ServiceId, string ServiceProvider,
1356 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1357 {
1358 return this.InitiateGetOptionsBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
1359 }
1360
1373 public Task InitiateGetOptionsBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1374 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1375 {
1376 if (!string.IsNullOrEmpty(SuccessUrl))
1377 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
1378
1379 if (!string.IsNullOrEmpty(FailureUrl))
1380 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
1381
1382 if (!string.IsNullOrEmpty(CancelUrl))
1383 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
1384
1385 StringBuilder Xml = new StringBuilder();
1386
1387 Xml.Append("<initiateGetOptionsBuyEDaler xmlns='");
1388 Xml.Append(NamespaceEDaler);
1389 Xml.Append("' serviceId='");
1390 Xml.Append(XML.Encode(ServiceId));
1391 Xml.Append("' serviceProvider='");
1392 Xml.Append(XML.Encode(ServiceProvider));
1393
1394 if (!string.IsNullOrEmpty(TransactionId))
1395 {
1396 Xml.Append("' tid='");
1397 Xml.Append(XML.Encode(TransactionId));
1398 }
1399
1400 if (!string.IsNullOrEmpty(SuccessUrl))
1401 {
1402 Xml.Append("' successUrl='");
1403 Xml.Append(XML.Encode(SuccessUrl));
1404 }
1405
1406 if (!string.IsNullOrEmpty(FailureUrl))
1407 {
1408 Xml.Append("' failureUrl='");
1409 Xml.Append(XML.Encode(FailureUrl));
1410 }
1411
1412 if (!string.IsNullOrEmpty(CancelUrl))
1413 {
1414 Xml.Append("' cancelUrl='");
1415 Xml.Append(XML.Encode(CancelUrl));
1416 }
1417
1418 Xml.Append("'/>");
1419
1420 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (Sender, e) =>
1421 {
1422 TransactionId = null;
1423 XmlElement E;
1424
1425 if (e.Ok &&
1426 !((E = e.FirstElement) is null) &&
1427 E.LocalName == "transaction" &&
1428 E.NamespaceURI == NamespaceEDaler)
1429 {
1430 TransactionId = XML.Attribute(E, "tid");
1431 }
1432 else
1433 e.Ok = false;
1434
1435 await Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
1436
1437 }, State);
1438 }
1439
1448 public Task<string> InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider)
1449 {
1450 return this.InitiateGetOptionsBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, null, null, null, null);
1451 }
1452
1465 public Task<string> InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider,
1466 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1467 {
1468 return this.InitiateGetOptionsBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
1469 }
1470
1484 public async Task<string> InitiateGetOptionsBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
1485 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1486 {
1487 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
1488
1489 await this.InitiateGetOptionsBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
1490 (Sender, e) =>
1491 {
1492 if (e.Ok)
1493 Result.TrySetResult(e.TransactionId);
1494 else
1495 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
1496
1497 return Task.CompletedTask;
1498 }, null);
1499
1500 return await Result.Task;
1501 }
1502
1503 private Task BuyEDalerOptionsClientUrlEventHandler(object Sender, MessageEventArgs e)
1504 {
1505 string TransactionId = XML.Attribute(e.Content, "tid");
1506 string Url = XML.Attribute(e.Content, "url");
1507
1508 return this.BuyEDalerOptionsClientUrlReceived.Raise(this, new BuyEDalerClientUrlEventArgs(e, TransactionId, Url));
1509 }
1510
1517 public event EventHandlerAsync<BuyEDalerClientUrlEventArgs> BuyEDalerOptionsClientUrlReceived;
1518
1519 private async Task BuyEDalerOptionsCompletedEventHandler(object Sender, MessageEventArgs e)
1520 {
1521 string TransactionId = XML.Attribute(e.Content, "tid");
1522 List<Dictionary<CaseInsensitiveString, object>> Options = new List<Dictionary<CaseInsensitiveString, object>>();
1523
1524 foreach (XmlNode N in e.Content.ChildNodes)
1525 {
1526 if (N is XmlElement E && E.LocalName == "option" && E.NamespaceURI == NamespaceEDaler)
1527 {
1528 Dictionary<CaseInsensitiveString, object> Option = new Dictionary<CaseInsensitiveString, object>();
1530
1531 foreach (XmlNode N2 in E.ChildNodes)
1532 {
1533 if (N2 is XmlElement E2 && E2.LocalName == "variable" && E2.NamespaceURI == NamespaceEDaler)
1534 {
1535 string Name = XML.Attribute(E2, "name");
1536 object Value = await ParseVariable(E2, Variables);
1537
1538 Option[Name] = Value;
1539 }
1540 }
1541
1542 Options.Add(Option);
1543 }
1544 }
1545
1546 await this.BuyEDalerOptionsCompleted.Raise(this, new PaymentOptionsEventArgs(e, TransactionId, Options.ToArray()));
1547 }
1548
1549 private async static Task<object> ParseVariable(XmlElement VariableDefinition, Variables Variables)
1550 {
1551 object Value = null;
1552
1553 foreach (XmlNode N2 in VariableDefinition.ChildNodes)
1554 {
1555 if (!(N2 is XmlElement E2))
1556 continue;
1557
1558 switch (E2.LocalName)
1559 {
1560 case "null":
1561 Value = null;
1562 break;
1563
1564 case "dbl":
1565 if (CommonTypes.TryParse(E2.InnerText, out double dbl))
1566 Value = dbl;
1567 break;
1568
1569 case "fl":
1570 if (CommonTypes.TryParse(E2.InnerText, out float fl))
1571 Value = fl;
1572 break;
1573
1574 case "dec":
1575 if (CommonTypes.TryParse(E2.InnerText, out decimal dec))
1576 Value = dec;
1577 break;
1578
1579 case "i8":
1580 if (sbyte.TryParse(E2.InnerText, out sbyte i8))
1581 Value = i8;
1582 break;
1583
1584 case "i16":
1585 if (short.TryParse(E2.InnerText, out short i16))
1586 Value = i16;
1587 break;
1588
1589 case "i32":
1590 if (int.TryParse(E2.InnerText, out int i32))
1591 Value = i32;
1592 break;
1593
1594 case "i64":
1595 if (long.TryParse(E2.InnerText, out long i64))
1596 Value = i64;
1597 break;
1598
1599 case "ui8":
1600 if (byte.TryParse(E2.InnerText, out byte ui8))
1601 Value = ui8;
1602 break;
1603
1604 case "ui16":
1605 if (ushort.TryParse(E2.InnerText, out ushort ui16))
1606 Value = ui16;
1607 break;
1608
1609 case "ui32":
1610 if (uint.TryParse(E2.InnerText, out uint ui32))
1611 Value = ui32;
1612 break;
1613
1614 case "ui64":
1615 if (ulong.TryParse(E2.InnerText, out ulong ui64))
1616 Value = ui64;
1617 break;
1618
1619 case "b":
1620 if (CommonTypes.TryParse(E2.InnerText, out bool b))
1621 Value = b;
1622 break;
1623
1624 case "dt":
1625 if (XML.TryParse(E2.InnerText, out DateTime TP))
1626 Value = TP;
1627 break;
1628
1629 case "dto":
1630 if (XML.TryParse(E2.InnerText, out DateTimeOffset TPO))
1631 Value = TPO;
1632 break;
1633
1634 case "ts":
1635 if (TimeSpan.TryParse(E2.InnerText, out TimeSpan TS))
1636 Value = TS;
1637 break;
1638
1639 case "d":
1640 if (Duration.TryParse(E2.InnerText, out Duration D))
1641 Value = D;
1642 break;
1643
1644 case "s":
1645 Value = E2.InnerText;
1646 break;
1647
1648 case "exp":
1649 try
1650 {
1651 Expression Exp = new Expression(E2.InnerText);
1652 Value = await Exp.EvaluateAsync(Variables);
1653 }
1654 catch (Exception)
1655 {
1656 Value = E2.InnerText;
1657 }
1658 break;
1659 }
1660 }
1661
1662 return Value;
1663 }
1664
1669 public event EventHandlerAsync<PaymentOptionsEventArgs> BuyEDalerOptionsCompleted;
1670
1671 private Task BuyEDalerOptionsErrorEventHandler(object Sender, MessageEventArgs e)
1672 {
1673 string TransactionId = XML.Attribute(e.Content, "tid");
1674 string Error = e.Content.InnerText;
1675
1676 return this.BuyEDalerOptionsError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
1677 }
1678
1683 public event EventHandlerAsync<PaymentErrorEventArgs> BuyEDalerOptionsError;
1684
1685 #endregion
1686
1687 #region Initiation of getting Payment options for selling eDaler using smart contracts
1688
1696 public Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider,
1697 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1698 {
1699 return this.InitiateGetOptionsSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Callback, State);
1700 }
1701
1710 public Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1711 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1712 {
1713 return this.InitiateGetOptionsSellEDaler(ComponentAddress, ServiceId, ServiceProvider, null, null, null, null, Callback, State);
1714 }
1715
1727 public Task InitiateGetOptionsSellEDaler(string ServiceId, string ServiceProvider,
1728 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1729 {
1730 return this.InitiateGetOptionsSellEDaler(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
1731 }
1732
1745 public Task InitiateGetOptionsSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1746 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1747 {
1748 if (!string.IsNullOrEmpty(SuccessUrl))
1749 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
1750
1751 if (!string.IsNullOrEmpty(FailureUrl))
1752 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
1753
1754 if (!string.IsNullOrEmpty(CancelUrl))
1755 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
1756
1757 StringBuilder Xml = new StringBuilder();
1758
1759 Xml.Append("<initiateGetOptionsSellEDaler xmlns='");
1760 Xml.Append(NamespaceEDaler);
1761 Xml.Append("' serviceId='");
1762 Xml.Append(XML.Encode(ServiceId));
1763 Xml.Append("' serviceProvider='");
1764 Xml.Append(XML.Encode(ServiceProvider));
1765
1766 if (!string.IsNullOrEmpty(TransactionId))
1767 {
1768 Xml.Append("' tid='");
1769 Xml.Append(XML.Encode(TransactionId));
1770 }
1771
1772 if (!string.IsNullOrEmpty(SuccessUrl))
1773 {
1774 Xml.Append("' successUrl='");
1775 Xml.Append(XML.Encode(SuccessUrl));
1776 }
1777
1778 if (!string.IsNullOrEmpty(FailureUrl))
1779 {
1780 Xml.Append("' failureUrl='");
1781 Xml.Append(XML.Encode(FailureUrl));
1782 }
1783
1784 if (!string.IsNullOrEmpty(CancelUrl))
1785 {
1786 Xml.Append("' cancelUrl='");
1787 Xml.Append(XML.Encode(CancelUrl));
1788 }
1789
1790 Xml.Append("'/>");
1791
1792 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
1793 {
1794 TransactionId = null;
1795 XmlElement E;
1796
1797 if (e.Ok &&
1798 !((E = e.FirstElement) is null) &&
1799 E.LocalName == "transaction" &&
1800 E.NamespaceURI == NamespaceEDaler)
1801 {
1802 TransactionId = XML.Attribute(E, "tid");
1803 }
1804 else
1805 e.Ok = false;
1806
1807 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
1808
1809 }, State);
1810 }
1811
1820 public Task<string> InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider)
1821 {
1822 return this.InitiateGetOptionsSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, null, null, null, null);
1823 }
1824
1837 public Task<string> InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider,
1838 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1839 {
1840 return this.InitiateGetOptionsSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
1841 }
1842
1856 public async Task<string> InitiateGetOptionsSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
1857 string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
1858 {
1859 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
1860
1861 await this.InitiateGetOptionsSellEDaler(ComponentAddress, ServiceId, ServiceProvider, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
1862 (Sender, e) =>
1863 {
1864 if (e.Ok)
1865 Result.TrySetResult(e.TransactionId);
1866 else
1867 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
1868
1869 return Task.CompletedTask;
1870 }, null);
1871
1872 return await Result.Task;
1873 }
1874
1875 private Task SellEDalerOptionsClientUrlEventHandler(object Sender, MessageEventArgs e)
1876 {
1877 string TransactionId = XML.Attribute(e.Content, "tid");
1878 string Url = XML.Attribute(e.Content, "url");
1879
1880 return this.SellEDalerOptionsClientUrlReceived.Raise(this, new SellEDalerClientUrlEventArgs(e, TransactionId, Url));
1881 }
1882
1889 public event EventHandlerAsync<SellEDalerClientUrlEventArgs> SellEDalerOptionsClientUrlReceived;
1890
1891 private async Task SellEDalerOptionsCompletedEventHandler(object Sender, MessageEventArgs e)
1892 {
1893 string TransactionId = XML.Attribute(e.Content, "tid");
1894 List<Dictionary<CaseInsensitiveString, object>> Options = new List<Dictionary<CaseInsensitiveString, object>>();
1895
1896 foreach (XmlNode N in e.Content.ChildNodes)
1897 {
1898 if (N is XmlElement E && E.LocalName == "option" && E.NamespaceURI == NamespaceEDaler)
1899 {
1900 Dictionary<CaseInsensitiveString, object> Option = new Dictionary<CaseInsensitiveString, object>();
1902
1903 foreach (XmlNode N2 in E.ChildNodes)
1904 {
1905 if (N2 is XmlElement E2 && E2.LocalName == "variable" && E2.NamespaceURI == NamespaceEDaler)
1906 {
1907 string Name = XML.Attribute(E2, "name");
1908 object Value = await ParseVariable(E2, Variables);
1909
1910 Option[Name] = Value;
1911 }
1912 }
1913
1914 Options.Add(Option);
1915 }
1916 }
1917
1918 await this.SellEDalerOptionsCompleted.Raise(this, new PaymentOptionsEventArgs(e, TransactionId, Options.ToArray()));
1919 }
1920
1925 public event EventHandlerAsync<PaymentOptionsEventArgs> SellEDalerOptionsCompleted;
1926
1927 private Task SellEDalerOptionsErrorEventHandler(object Sender, MessageEventArgs e)
1928 {
1929 string TransactionId = XML.Attribute(e.Content, "tid");
1930 string Error = e.Content.InnerText;
1931
1932 return this.SellEDalerOptionsError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
1933 }
1934
1939 public event EventHandlerAsync<PaymentErrorEventArgs> SellEDalerOptionsError;
1940
1941 #endregion
1942
1943 #region Initiation of buying eDaler using non-contract based services
1944
1954 public Task InitiateBuyEDaler(string ServiceId, string ServiceProvider,
1955 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1956 {
1957 return this.InitiateBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, Callback, State);
1958 }
1959
1970 public Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
1971 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1972 {
1973 return this.InitiateBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null, Callback, State);
1974 }
1975
1989 public Task InitiateBuyEDaler(string ServiceId, string ServiceProvider,
1990 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
1991 {
1992 return this.InitiateBuyEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
1993 }
1994
2009 public Task InitiateBuyEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2010 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2011 {
2012 if (!string.IsNullOrEmpty(SuccessUrl))
2013 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
2014
2015 if (!string.IsNullOrEmpty(FailureUrl))
2016 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
2017
2018 if (!string.IsNullOrEmpty(CancelUrl))
2019 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
2020
2021 StringBuilder Xml = new StringBuilder();
2022
2023 Xml.Append("<initiateBuyEDaler xmlns='");
2024 Xml.Append(NamespaceEDaler);
2025 Xml.Append("' serviceId='");
2026 Xml.Append(XML.Encode(ServiceId));
2027 Xml.Append("' serviceProvider='");
2028 Xml.Append(XML.Encode(ServiceProvider));
2029 Xml.Append("' amount='");
2030 Xml.Append(CommonTypes.Encode(Amount));
2031 Xml.Append("' currency='");
2032 Xml.Append(XML.Encode(Currency));
2033
2034 if (!string.IsNullOrEmpty(TransactionId))
2035 {
2036 Xml.Append("' tid='");
2037 Xml.Append(XML.Encode(TransactionId));
2038 }
2039
2040 if (!string.IsNullOrEmpty(SuccessUrl))
2041 {
2042 Xml.Append("' successUrl='");
2043 Xml.Append(XML.Encode(SuccessUrl));
2044 }
2045
2046 if (!string.IsNullOrEmpty(FailureUrl))
2047 {
2048 Xml.Append("' failureUrl='");
2049 Xml.Append(XML.Encode(FailureUrl));
2050 }
2051
2052 if (!string.IsNullOrEmpty(CancelUrl))
2053 {
2054 Xml.Append("' cancelUrl='");
2055 Xml.Append(XML.Encode(CancelUrl));
2056 }
2057
2058 Xml.Append("'/>");
2059
2060 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
2061 {
2062 TransactionId = null;
2063 XmlElement E;
2064
2065 if (e.Ok &&
2066 !((E = e.FirstElement) is null) &&
2067 E.LocalName == "transaction" &&
2068 E.NamespaceURI == NamespaceEDaler)
2069 {
2070 TransactionId = XML.Attribute(E, "tid");
2071 }
2072 else
2073 e.Ok = false;
2074
2075 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
2076
2077 }, State);
2078 }
2079
2090 public Task<string> InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
2091 {
2092 return this.InitiateBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency);
2093 }
2094
2106 public Task<string> InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2107 decimal Amount, string Currency)
2108 {
2109 return this.InitiateBuyEDalerAsync(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null);
2110 }
2111
2126 public Task<string> InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider,
2127 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2128 {
2129 return this.InitiateBuyEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
2130 }
2131
2147 public async Task<string> InitiateBuyEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2148 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2149 {
2150 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
2151
2152 await this.InitiateBuyEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
2153 (Sender, e) =>
2154 {
2155 if (e.Ok)
2156 Result.TrySetResult(e.TransactionId);
2157 else
2158 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
2159
2160 return Task.CompletedTask;
2161 }, null);
2162
2163 return await Result.Task;
2164 }
2165
2166 private Task BuyEDalerClientUrlEventHandler(object Sender, MessageEventArgs e)
2167 {
2168 string TransactionId = XML.Attribute(e.Content, "tid");
2169 string Url = XML.Attribute(e.Content, "url");
2170
2171 return this.BuyEDalerClientUrlReceived.Raise(this, new BuyEDalerClientUrlEventArgs(e, TransactionId, Url));
2172 }
2173
2179 public event EventHandlerAsync<BuyEDalerClientUrlEventArgs> BuyEDalerClientUrlReceived;
2180
2181 private Task BuyEDalerCompletedEventHandler(object Sender, MessageEventArgs e)
2182 {
2183 string TransactionId = XML.Attribute(e.Content, "tid");
2184 string Currency = XML.Attribute(e.Content, "currency");
2185 decimal Amount = XML.Attribute(e.Content, "amount", 0M);
2186
2187 return this.BuyEDalerCompleted.Raise(this, new PaymentCompletedEventArgs(e, TransactionId, Amount, Currency));
2188 }
2189
2194 public event EventHandlerAsync<PaymentCompletedEventArgs> BuyEDalerCompleted;
2195
2196 private Task BuyEDalerErrorEventHandler(object Sender, MessageEventArgs e)
2197 {
2198 string TransactionId = XML.Attribute(e.Content, "tid");
2199 string Error = e.Content.InnerText;
2200
2201 return this.BuyEDalerError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
2202 }
2203
2208 public event EventHandlerAsync<PaymentErrorEventArgs> BuyEDalerError;
2209
2210 #endregion
2211
2212 #region Initiation of selling eDaler using non-contract based services
2213
2223 public Task InitiateSellEDaler(string ServiceId, string ServiceProvider,
2224 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2225 {
2226 return this.InitiateSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, Callback, State);
2227 }
2228
2239 public Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2240 decimal Amount, string Currency, EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2241 {
2242 return this.InitiateSellEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null, Callback, State);
2243 }
2244
2258 public Task InitiateSellEDaler(string ServiceId, string ServiceProvider,
2259 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl,
2260 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2261 {
2262 return this.InitiateSellEDaler(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl, Callback, State);
2263 }
2264
2279 public Task InitiateSellEDaler(string ComponentAddress, string ServiceId, string ServiceProvider,
2280 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl,
2281 EventHandlerAsync<TransactionIdEventArgs> Callback, object State)
2282 {
2283 if (!string.IsNullOrEmpty(SuccessUrl))
2284 SuccessUrl = SuccessUrl.Replace("{TID}", TransactionId);
2285
2286 if (!string.IsNullOrEmpty(FailureUrl))
2287 FailureUrl = FailureUrl.Replace("{TID}", TransactionId);
2288
2289 if (!string.IsNullOrEmpty(CancelUrl))
2290 CancelUrl = CancelUrl.Replace("{TID}", TransactionId);
2291
2292 StringBuilder Xml = new StringBuilder();
2293
2294 Xml.Append("<initiateSellEDaler xmlns='");
2295 Xml.Append(NamespaceEDaler);
2296 Xml.Append("' serviceId='");
2297 Xml.Append(XML.Encode(ServiceId));
2298 Xml.Append("' serviceProvider='");
2299 Xml.Append(XML.Encode(ServiceProvider));
2300 Xml.Append("' amount='");
2301 Xml.Append(CommonTypes.Encode(Amount));
2302 Xml.Append("' currency='");
2303 Xml.Append(XML.Encode(Currency));
2304
2305 if (!string.IsNullOrEmpty(TransactionId))
2306 {
2307 Xml.Append("' tid='");
2308 Xml.Append(XML.Encode(TransactionId));
2309 }
2310
2311 if (!string.IsNullOrEmpty(SuccessUrl))
2312 {
2313 Xml.Append("' successUrl='");
2314 Xml.Append(XML.Encode(SuccessUrl));
2315 }
2316
2317 if (!string.IsNullOrEmpty(FailureUrl))
2318 {
2319 Xml.Append("' failureUrl='");
2320 Xml.Append(XML.Encode(FailureUrl));
2321 }
2322
2323 if (!string.IsNullOrEmpty(CancelUrl))
2324 {
2325 Xml.Append("' cancelUrl='");
2326 Xml.Append(XML.Encode(CancelUrl));
2327 }
2328
2329 Xml.Append("'/>");
2330
2331 return this.client.SendIqSet(ComponentAddress, Xml.ToString(), (Sender, e) =>
2332 {
2333 TransactionId = null;
2334 XmlElement E;
2335
2336 if (e.Ok &&
2337 !((E = e.FirstElement) is null) &&
2338 E.LocalName == "transaction" &&
2339 E.NamespaceURI == NamespaceEDaler)
2340 {
2341 TransactionId = XML.Attribute(E, "tid");
2342 }
2343 else
2344 e.Ok = false;
2345
2346 return Callback.Raise(this, new TransactionIdEventArgs(e, TransactionId));
2347
2348 }, State);
2349 }
2350
2361 public Task<string> InitiateSellEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
2362 {
2363 return this.InitiateSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency);
2364 }
2365
2376 public Task<string> InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2377 decimal Amount, string Currency)
2378 {
2379 return this.InitiateSellEDalerAsync(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, null, null, null, null);
2380 }
2381
2395 public Task<string> InitiateSellEDalerAsync(string ServiceId, string ServiceProvider,
2396 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2397 {
2398 return this.InitiateSellEDalerAsync(this.componentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl);
2399 }
2400
2415 public async Task<string> InitiateSellEDalerAsync(string ComponentAddress, string ServiceId, string ServiceProvider,
2416 decimal Amount, string Currency, string TransactionId, string SuccessUrl, string FailureUrl, string CancelUrl)
2417 {
2418 TaskCompletionSource<string> Result = new TaskCompletionSource<string>();
2419
2420 await this.InitiateSellEDaler(ComponentAddress, ServiceId, ServiceProvider, Amount, Currency, TransactionId, SuccessUrl, FailureUrl, CancelUrl,
2421 (Sender, e) =>
2422 {
2423 if (e.Ok)
2424 Result.TrySetResult(e.TransactionId);
2425 else
2426 Result.TrySetException(e.StanzaError ?? new Exception("Unable to initiate payment process."));
2427
2428 return Task.CompletedTask;
2429 }, null);
2430
2431 return await Result.Task;
2432 }
2433
2434 private Task SellEDalerClientUrlEventHandler(object Sender, MessageEventArgs e)
2435 {
2436 string TransactionId = XML.Attribute(e.Content, "tid");
2437 string Url = XML.Attribute(e.Content, "url");
2438
2439 return this.SellEDalerClientUrlReceived.Raise(this, new SellEDalerClientUrlEventArgs(e, TransactionId, Url));
2440 }
2441
2447 public event EventHandlerAsync<SellEDalerClientUrlEventArgs> SellEDalerClientUrlReceived;
2448
2449 private Task SellEDalerCompletedEventHandler(object Sender, MessageEventArgs e)
2450 {
2451 string TransactionId = XML.Attribute(e.Content, "tid");
2452 string Currency = XML.Attribute(e.Content, "currency");
2453 decimal Amount = XML.Attribute(e.Content, "amount", 0M);
2454
2455 return this.SellEDalerCompleted.Raise(this, new PaymentCompletedEventArgs(e, TransactionId, Amount, Currency));
2456 }
2457
2462 public event EventHandlerAsync<PaymentCompletedEventArgs> SellEDalerCompleted;
2463
2464 private Task SellEDalerErrorEventHandler(object Sender, MessageEventArgs e)
2465 {
2466 string TransactionId = XML.Attribute(e.Content, "tid");
2467 string Error = e.Content.InnerText;
2468
2469 return this.SellEDalerError.Raise(this, new PaymentErrorEventArgs(e, TransactionId, Error));
2470 }
2471
2476 public event EventHandlerAsync<PaymentErrorEventArgs> SellEDalerError;
2477
2478 #endregion
2479
2480 }
2481}
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:24
override string[] Extensions
Implemented extensions.
Definition: EDalerClient.cs:94
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:43
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...
async Task< string > DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId)
Decrypts a message that was aimed at the client using the current keys.
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.
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:28
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:67
async Task< Transaction > SendEDalerUriAsync(string ComponentAddress, string Uri)
Sends an eDaler URI to the server
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...
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.
async Task< string > CreateFullPaymentUri(LegalIdentity ToLegalId, decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays, string PrivateMessage)
Creates a full payment URI.
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:89
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.
async Task< string > DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId, string RemoteEndpoint)
Decrypts a message that was aimed at the client using the current keys.
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:13
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:594
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Definition: XML.cs:744
Class representing an event.
Definition: Event.cs:10
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
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:1647
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:59
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters a Message handler.
Definition: XmppClient.cs:2855
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers a Message handler.
Definition: XmppClient.cs:2828
Task< uint > SendIqSet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Set request.
Definition: XmppClient.cs:3607
Task< uint > SendIqGet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Get request.
Definition: XmppClient.cs:3559
Base class for XMPP Extensions.
XmppClient client
XMPP Client used by the extension.
Task 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:39
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
Definition: Expression.cs:4275
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:84
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13
static bool TryParse(string s, out Duration Result)
Tries to parse a duration value.
Definition: Duration.cs:85