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" }); }
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" }); }
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" }); }