public async Task <IActionResult> GetRates2(string cryptoCode = null, string storeId = null)
        {
            cryptoCode = cryptoCode ?? "BTC";
            var network = _NetworkProvider.GetNetwork(cryptoCode);

            if (network == null)
            {
                return(NotFound());
            }

            RateRules rules = null;

            if (storeId != null)
            {
                var store = await _StoreRepo.FindStore(storeId);

                if (store == null)
                {
                    return(NotFound());
                }
                rules = store.GetStoreBlob().GetRateRules();
            }

            var rateProvider = _RateProviderFactory.GetRateProvider(network, rules);

            if (rateProvider == null)
            {
                return(NotFound());
            }

            var allRates = (await rateProvider.GetRatesAsync());

            return(Json(allRates.Select(r =>
                                        new NBitpayClient.Rate()
            {
                Code = r.Currency,
                Name = _CurrencyNameTable.GetCurrencyData(r.Currency)?.Name,
                Value = r.Value
            }).Where(n => n.Name != null).ToArray()));
        }
        internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
        {
            var entity = new InvoiceEntity
            {
                InvoiceTime = DateTimeOffset.UtcNow
            };

            var storeBlob       = store.GetStoreBlob();
            Uri notificationUri = Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute) ? new Uri(invoice.NotificationURL, UriKind.Absolute) : null;

            if (notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
            {
                notificationUri = null;
            }
            EmailAddressAttribute emailValidator = new EmailAddressAttribute();

            entity.ExpirationTime       = entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration);
            entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
            entity.OrderId               = invoice.OrderId;
            entity.ServerUrl             = serverUrl;
            entity.FullNotifications     = invoice.FullNotifications || invoice.ExtendedNotifications;
            entity.ExtendedNotifications = invoice.ExtendedNotifications;
            entity.NotificationURL       = notificationUri?.AbsoluteUri;
            entity.BuyerInformation      = Map <Invoice, BuyerInformation>(invoice);
            //Another way of passing buyer info to support
            FillBuyerInfo(invoice.Buyer, entity.BuyerInformation);
            if (entity?.BuyerInformation?.BuyerEmail != null)
            {
                if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail))
                {
                    throw new BitpayHttpException(400, "Invalid email");
                }
                entity.RefundMail = entity.BuyerInformation.BuyerEmail;
            }
            entity.ProductInformation = Map <Invoice, ProductInformation>(invoice);
            entity.RedirectURL        = invoice.RedirectURL ?? store.StoreWebsite;
            entity.Status             = "new";
            entity.SpeedPolicy        = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);


            var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider)
                                          .Select(c =>
                                                  (Handler: (IPaymentMethodHandler)_ServiceProvider.GetService(typeof(IPaymentMethodHandler <>).MakeGenericType(c.GetType())),
                                                   SupportedPaymentMethod: c,
                                                   Network: _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode)))
                                          .Where(c => c.Network != null)
                                          .Select(o =>
                                                  (SupportedPaymentMethod: o.SupportedPaymentMethod,
                                                   PaymentMethod: CreatePaymentMethodAsync(o.Handler, o.SupportedPaymentMethod, o.Network, entity, store)))
                                          .ToList();

            List <string> paymentMethodErrors        = new List <string>();
            List <ISupportedPaymentMethod> supported = new List <ISupportedPaymentMethod>();
            var paymentMethods = new PaymentMethodDictionary();

            foreach (var o in supportedPaymentMethods)
            {
                try
                {
                    var paymentMethod = await o.PaymentMethod;
                    if (paymentMethod == null)
                    {
                        throw new PaymentMethodUnavailableException("Payment method unavailable (The handler returned null)");
                    }
                    supported.Add(o.SupportedPaymentMethod);
                    paymentMethods.Add(paymentMethod);
                }
                catch (PaymentMethodUnavailableException ex)
                {
                    paymentMethodErrors.Add($"{o.SupportedPaymentMethod.PaymentId.CryptoCode} ({o.SupportedPaymentMethod.PaymentId.PaymentType}): Payment method unavailable ({ex.Message})");
                }
                catch (Exception ex)
                {
                    paymentMethodErrors.Add($"{o.SupportedPaymentMethod.PaymentId.CryptoCode} ({o.SupportedPaymentMethod.PaymentId.PaymentType}): Unexpected exception ({ex.ToString()})");
                }
            }

            if (supported.Count == 0)
            {
                StringBuilder errors = new StringBuilder();
                errors.AppendLine("No payment method available for this store");
                foreach (var error in paymentMethodErrors)
                {
                    errors.AppendLine(error);
                }
                throw new BitpayHttpException(400, errors.ToString());
            }

            entity.SetSupportedPaymentMethods(supported);
            entity.SetPaymentMethods(paymentMethods);
#pragma warning disable CS0618
            // Legacy Bitpay clients expect information for BTC information, even if the store do not support it
            var legacyBTCisSet = paymentMethods.Any(p => p.GetId().IsBTCOnChain);
            if (!legacyBTCisSet && _NetworkProvider.BTC != null)
            {
                var btc          = _NetworkProvider.BTC;
                var feeProvider  = ((IFeeProviderFactory)_ServiceProvider.GetService(typeof(IFeeProviderFactory))).CreateFeeProvider(btc);
                var rateProvider = _RateProviders.GetRateProvider(btc, storeBlob.GetRateRules());
                if (feeProvider != null && rateProvider != null)
                {
                    var gettingFee  = feeProvider.GetFeeRateAsync();
                    var gettingRate = rateProvider.GetRateAsync(invoice.Currency);
                    entity.TxFee = GetTxFee(storeBlob, await gettingFee);
                    entity.Rate  = await gettingRate;
                }
#pragma warning restore CS0618
            }
            entity.PosData = invoice.PosData;
            entity         = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, paymentMethodErrors, _NetworkProvider);

            _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created"));
            var resp = entity.EntityToDTO(_NetworkProvider);
            return(new DataWrapper <InvoiceResponse>(resp)
            {
                Facade = "pos/invoice"
            });
        }
        internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15)
        {
            var derivationStrategies = store.GetDerivationStrategies(_NetworkProvider).ToList();

            if (derivationStrategies.Count == 0)
            {
                throw new BitpayHttpException(400, "This store has not configured the derivation strategy");
            }
            var entity = new InvoiceEntity
            {
                InvoiceTime = DateTimeOffset.UtcNow
            };

            entity.SetDerivationStrategies(derivationStrategies);

            var storeBlob       = store.GetStoreBlob();
            Uri notificationUri = Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute) ? new Uri(invoice.NotificationURL, UriKind.Absolute) : null;

            if (notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
            {
                notificationUri = null;
            }
            EmailAddressAttribute emailValidator = new EmailAddressAttribute();

            entity.ExpirationTime       = entity.InvoiceTime.AddMinutes(expiryMinutes);
            entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
            entity.OrderId               = invoice.OrderId;
            entity.ServerUrl             = serverUrl;
            entity.FullNotifications     = invoice.FullNotifications || invoice.ExtendedNotifications;
            entity.ExtendedNotifications = invoice.ExtendedNotifications;
            entity.NotificationURL       = notificationUri?.AbsoluteUri;
            entity.BuyerInformation      = Map <Invoice, BuyerInformation>(invoice);
            //Another way of passing buyer info to support
            FillBuyerInfo(invoice.Buyer, entity.BuyerInformation);
            if (entity?.BuyerInformation?.BuyerEmail != null)
            {
                if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail))
                {
                    throw new BitpayHttpException(400, "Invalid email");
                }
                entity.RefundMail = entity.BuyerInformation.BuyerEmail;
            }
            entity.ProductInformation = Map <Invoice, ProductInformation>(invoice);
            entity.RedirectURL        = invoice.RedirectURL ?? store.StoreWebsite;
            entity.Status             = "new";
            entity.SpeedPolicy        = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);

            var queries = derivationStrategies
                          .Select(derivationStrategy =>
            {
                return(new
                {
                    network = derivationStrategy.Network,
                    getFeeRate = _FeeProviderFactory.CreateFeeProvider(derivationStrategy.Network).GetFeeRateAsync(),
                    getRate = _RateProviders.GetRateProvider(derivationStrategy.Network).GetRateAsync(invoice.Currency),
                    getAddress = _Wallet.ReserveAddressAsync(derivationStrategy)
                });
            });

            var cryptoDatas = new Dictionary <string, CryptoData>();

            foreach (var q in queries)
            {
                CryptoData cryptoData = new CryptoData();
                cryptoData.CryptoCode     = q.network.CryptoCode;
                cryptoData.FeeRate        = (await q.getFeeRate);
                cryptoData.TxFee          = storeBlob.NetworkFeeDisabled ? Money.Zero : cryptoData.FeeRate.GetFee(100); // assume price for 100 bytes
                cryptoData.Rate           = await q.getRate;
                cryptoData.DepositAddress = (await q.getAddress).ToString();

#pragma warning disable CS0618
                if (q.network.IsBTC)
                {
                    entity.TxFee          = cryptoData.TxFee;
                    entity.Rate           = cryptoData.Rate;
                    entity.DepositAddress = cryptoData.DepositAddress;
                }
#pragma warning restore CS0618
                cryptoDatas.Add(cryptoData.CryptoCode, cryptoData);
            }
            entity.SetCryptoData(cryptoDatas);
            entity.PosData = invoice.PosData;
            entity         = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, _NetworkProvider);

            _EventAggregator.Publish(new Events.InvoiceCreatedEvent(entity.Id));
            var resp = entity.EntityToDTO(_NetworkProvider);
            return(new DataWrapper <InvoiceResponse>(resp)
            {
                Facade = "pos/invoice"
            });
        }
Beispiel #4
0
        internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
        {
            var derivationStrategies = store.GetDerivationStrategies(_NetworkProvider).Where(c => _ExplorerClients.IsAvailable(c.Network.CryptoCode)).ToList();

            if (derivationStrategies.Count == 0)
            {
                throw new BitpayHttpException(400, "No derivation strategy are available now for this store");
            }
            var entity = new InvoiceEntity
            {
                InvoiceTime = DateTimeOffset.UtcNow
            };

            entity.SetDerivationStrategies(derivationStrategies);

            var storeBlob       = store.GetStoreBlob();
            Uri notificationUri = Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute) ? new Uri(invoice.NotificationURL, UriKind.Absolute) : null;

            if (notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
            {
                notificationUri = null;
            }
            EmailAddressAttribute emailValidator = new EmailAddressAttribute();

            entity.ExpirationTime       = entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration);
            entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
            entity.OrderId               = invoice.OrderId;
            entity.ServerUrl             = serverUrl;
            entity.FullNotifications     = invoice.FullNotifications || invoice.ExtendedNotifications;
            entity.ExtendedNotifications = invoice.ExtendedNotifications;
            entity.NotificationURL       = notificationUri?.AbsoluteUri;
            entity.BuyerInformation      = Map <Invoice, BuyerInformation>(invoice);
            //Another way of passing buyer info to support
            FillBuyerInfo(invoice.Buyer, entity.BuyerInformation);
            if (entity?.BuyerInformation?.BuyerEmail != null)
            {
                if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail))
                {
                    throw new BitpayHttpException(400, "Invalid email");
                }
                entity.RefundMail = entity.BuyerInformation.BuyerEmail;
            }
            entity.ProductInformation = Map <Invoice, ProductInformation>(invoice);
            entity.RedirectURL        = invoice.RedirectURL ?? store.StoreWebsite;
            entity.Status             = "new";
            entity.SpeedPolicy        = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);

            var queries = derivationStrategies
                          .Select(derivationStrategy => (Wallet: _WalletProvider.GetWallet(derivationStrategy.Network),
                                                         DerivationStrategy: derivationStrategy.DerivationStrategyBase,
                                                         Network: derivationStrategy.Network,
                                                         RateProvider: _RateProviders.GetRateProvider(derivationStrategy.Network, false),
                                                         FeeRateProvider: _FeeProviderFactory.CreateFeeProvider(derivationStrategy.Network)))
                          .Where(_ => _.Wallet != null &&
                                 _.FeeRateProvider != null &&
                                 _.RateProvider != null)
                          .Select(_ =>
            {
                return(new
                {
                    network = _.Network,
                    getFeeRate = _.FeeRateProvider.GetFeeRateAsync(),
                    getRate = storeBlob.ApplyRateRules(_.Network, _.RateProvider).GetRateAsync(invoice.Currency),
                    getAddress = _.Wallet.ReserveAddressAsync(_.DerivationStrategy)
                });
            });

            bool legacyBTCisSet = false;
            var  cryptoDatas    = new Dictionary <string, CryptoData>();

            foreach (var q in queries)
            {
                CryptoData cryptoData = new CryptoData();
                cryptoData.CryptoCode     = q.network.CryptoCode;
                cryptoData.FeeRate        = (await q.getFeeRate);
                cryptoData.TxFee          = GetTxFee(storeBlob, cryptoData.FeeRate); // assume price for 100 bytes
                cryptoData.Rate           = await q.getRate;
                cryptoData.DepositAddress = (await q.getAddress).ToString();

#pragma warning disable CS0618
                if (q.network.IsBTC)
                {
                    legacyBTCisSet        = true;
                    entity.TxFee          = cryptoData.TxFee;
                    entity.Rate           = cryptoData.Rate;
                    entity.DepositAddress = cryptoData.DepositAddress;
                }
#pragma warning restore CS0618
                cryptoDatas.Add(cryptoData.CryptoCode, cryptoData);
            }

            if (!legacyBTCisSet)
            {
                // Legacy Bitpay clients expect information for BTC information, even if the store do not support it
#pragma warning disable CS0618
                var btc          = _NetworkProvider.BTC;
                var feeProvider  = _FeeProviderFactory.CreateFeeProvider(btc);
                var rateProvider = storeBlob.ApplyRateRules(btc, _RateProviders.GetRateProvider(btc, false));
                if (feeProvider != null && rateProvider != null)
                {
                    var gettingFee  = feeProvider.GetFeeRateAsync();
                    var gettingRate = rateProvider.GetRateAsync(invoice.Currency);
                    entity.TxFee = GetTxFee(storeBlob, await gettingFee);
                    entity.Rate  = await gettingRate;
                }
#pragma warning restore CS0618
            }

            entity.SetCryptoData(cryptoDatas);
            entity.PosData = invoice.PosData;
            entity         = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, _NetworkProvider);

            _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created"));
            var resp = entity.EntityToDTO(_NetworkProvider);
            return(new DataWrapper <InvoiceResponse>(resp)
            {
                Facade = "pos/invoice"
            });
        }
Beispiel #5
0
        internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
        {
            var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider)
                                          .Select(c =>
                                                  (Handler: (IPaymentMethodHandler)_ServiceProvider.GetService(typeof(IPaymentMethodHandler <>).MakeGenericType(c.GetType())),
                                                   SupportedPaymentMethod: c,
                                                   Network: _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode),
                                                   IsAvailable: Task.FromResult(false)))
                                          .Where(c => c.Network != null)
                                          .Select(c =>
            {
                c.IsAvailable = c.Handler.IsAvailable(c.SupportedPaymentMethod, c.Network);
                return(c);
            })
                                          .ToList();

            foreach (var supportedPaymentMethod in supportedPaymentMethods.ToList())
            {
                if (!await supportedPaymentMethod.IsAvailable)
                {
                    supportedPaymentMethods.Remove(supportedPaymentMethod);
                }
            }
            if (supportedPaymentMethods.Count == 0)
            {
                throw new BitpayHttpException(400, "No derivation strategy are available now for this store");
            }
            var entity = new InvoiceEntity
            {
                InvoiceTime = DateTimeOffset.UtcNow
            };

            entity.SetSupportedPaymentMethods(supportedPaymentMethods.Select(s => s.SupportedPaymentMethod));

            var storeBlob       = store.GetStoreBlob();
            Uri notificationUri = Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute) ? new Uri(invoice.NotificationURL, UriKind.Absolute) : null;

            if (notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
            {
                notificationUri = null;
            }
            EmailAddressAttribute emailValidator = new EmailAddressAttribute();

            entity.ExpirationTime       = entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration);
            entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
            entity.OrderId               = invoice.OrderId;
            entity.ServerUrl             = serverUrl;
            entity.FullNotifications     = invoice.FullNotifications || invoice.ExtendedNotifications;
            entity.ExtendedNotifications = invoice.ExtendedNotifications;
            entity.NotificationURL       = notificationUri?.AbsoluteUri;
            entity.BuyerInformation      = Map <Invoice, BuyerInformation>(invoice);
            //Another way of passing buyer info to support
            FillBuyerInfo(invoice.Buyer, entity.BuyerInformation);
            if (entity?.BuyerInformation?.BuyerEmail != null)
            {
                if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail))
                {
                    throw new BitpayHttpException(400, "Invalid email");
                }
                entity.RefundMail = entity.BuyerInformation.BuyerEmail;
            }
            entity.ProductInformation = Map <Invoice, ProductInformation>(invoice);
            entity.RedirectURL        = invoice.RedirectURL ?? store.StoreWebsite;
            entity.Status             = "new";
            entity.SpeedPolicy        = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);

            var methods = supportedPaymentMethods
                          .Select(async o =>
            {
                var rate = await storeBlob.ApplyRateRules(o.Network, _RateProviders.GetRateProvider(o.Network, false)).GetRateAsync(invoice.Currency);
                PaymentMethod paymentMethod = new PaymentMethod();
                paymentMethod.ParentEntity  = entity;
                paymentMethod.SetId(o.SupportedPaymentMethod.PaymentId);
                paymentMethod.Rate = rate;
                var paymentDetails = await o.Handler.CreatePaymentMethodDetails(o.SupportedPaymentMethod, paymentMethod, o.Network);
                if (storeBlob.NetworkFeeDisabled)
                {
                    paymentDetails.SetNoTxFee();
                }
                paymentMethod.SetPaymentMethodDetails(paymentDetails);
#pragma warning disable CS0618
                if (paymentMethod.GetId().IsBTCOnChain)
                {
                    entity.TxFee          = paymentMethod.TxFee;
                    entity.Rate           = paymentMethod.Rate;
                    entity.DepositAddress = paymentMethod.DepositAddress;
                }
#pragma warning restore CS0618
                return(paymentMethod);
            });
            var paymentMethods = new PaymentMethodDictionary();

            foreach (var method in methods)
            {
                paymentMethods.Add(await method);
            }
#pragma warning disable CS0618
            // Legacy Bitpay clients expect information for BTC information, even if the store do not support it
            var legacyBTCisSet = paymentMethods.Any(p => p.GetId().IsBTCOnChain);
            if (!legacyBTCisSet && _NetworkProvider.BTC != null)
            {
                var btc          = _NetworkProvider.BTC;
                var feeProvider  = ((IFeeProviderFactory)_ServiceProvider.GetService(typeof(IFeeProviderFactory))).CreateFeeProvider(btc);
                var rateProvider = storeBlob.ApplyRateRules(btc, _RateProviders.GetRateProvider(btc, false));
                if (feeProvider != null && rateProvider != null)
                {
                    var gettingFee  = feeProvider.GetFeeRateAsync();
                    var gettingRate = rateProvider.GetRateAsync(invoice.Currency);
                    entity.TxFee = GetTxFee(storeBlob, await gettingFee);
                    entity.Rate  = await gettingRate;
                }
#pragma warning restore CS0618
            }

            entity.SetPaymentMethods(paymentMethods);
            entity.PosData = invoice.PosData;
            entity         = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, _NetworkProvider);

            _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created"));
            var resp = entity.EntityToDTO(_NetworkProvider);
            return(new DataWrapper <InvoiceResponse>(resp)
            {
                Facade = "pos/invoice"
            });
        }