Beispiel #1
0
 public abstract string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData);
 public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str)
 {
     return(((BTCPayNetwork)network).ToObject <BitcoinLikeOnChainPaymentMethod>(str));
 }
Beispiel #3
0
 public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
 {
     return(((BTCPayNetwork)network).ToObject <LightningLikePaymentData>(str));
 }
Beispiel #4
0
 public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str)
 {
     return(JsonConvert.DeserializeObject <Payments.Lightning.LightningLikePaymentMethodDetails>(str));
 }
        //TODO: abstract
        private async Task <PaymentModel> GetInvoiceModel(string invoiceId, PaymentMethodId paymentMethodId)
        {
            var invoice = await _InvoiceRepository.GetInvoice(invoiceId);

            if (invoice == null)
            {
                return(null);
            }
            var store = await _StoreRepository.FindStore(invoice.StoreId);

            bool isDefaultPaymentId = false;

            if (paymentMethodId == null)
            {
                paymentMethodId    = store.GetDefaultPaymentId(_NetworkProvider);
                isDefaultPaymentId = true;
            }
            BTCPayNetworkBase network = _NetworkProvider.GetNetwork <BTCPayNetwork>(paymentMethodId.CryptoCode);

            if (network == null && isDefaultPaymentId)
            {
                //TODO: need to look into a better way for this as it does not scale
                network         = _NetworkProvider.GetAll().OfType <BTCPayNetwork>().FirstOrDefault();
                paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
            }
            if (invoice == null || network == null)
            {
                return(null);
            }
            if (!invoice.Support(paymentMethodId))
            {
                if (!isDefaultPaymentId)
                {
                    return(null);
                }
                var paymentMethodTemp = invoice.GetPaymentMethods()
                                        .Where(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode)
                                        .FirstOrDefault();
                if (paymentMethodTemp == null)
                {
                    paymentMethodTemp = invoice.GetPaymentMethods().First();
                }
                network         = paymentMethodTemp.Network;
                paymentMethodId = paymentMethodTemp.GetId();
            }

            var paymentMethod        = invoice.GetPaymentMethod(paymentMethodId);
            var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
            var dto        = invoice.EntityToDTO();
            var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
            var storeBlob  = store.GetStoreBlob();
            var currency   = invoice.ProductInformation.Currency;
            var accounting = paymentMethod.Calculate();

            ChangellySettings changelly = (storeBlob.ChangellySettings != null && storeBlob.ChangellySettings.Enabled &&
                                           storeBlob.ChangellySettings.IsConfigured())
                ? storeBlob.ChangellySettings
                : null;

            CoinSwitchSettings coinswitch = (storeBlob.CoinSwitchSettings != null && storeBlob.CoinSwitchSettings.Enabled &&
                                             storeBlob.CoinSwitchSettings.IsConfigured())
                ? storeBlob.CoinSwitchSettings
                : null;


            var changellyAmountDue = changelly != null
                ? (accounting.Due.ToDecimal(MoneyUnit.BTC) *
                   (1m + (changelly.AmountMarkupPercentage / 100m)))
                : (decimal?)null;


            var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId];
            var model = new PaymentModel()
            {
                CryptoCode               = network.CryptoCode,
                RootPath                 = this.Request.PathBase.Value.WithTrailingSlash(),
                OrderId                  = invoice.OrderId,
                InvoiceId                = invoice.Id,
                DefaultLang              = storeBlob.DefaultLang ?? "en",
                HtmlTitle                = storeBlob.HtmlTitle ?? "BTCPay Invoice",
                CustomCSSLink            = storeBlob.CustomCSS?.AbsoluteUri,
                CustomLogoLink           = storeBlob.CustomLogo?.AbsoluteUri,
                CryptoImage              = Request.GetRelativePathOrAbsolute(paymentMethodHandler.GetCryptoImage(paymentMethodId)),
                LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi,
                BtcAddress               = paymentMethodDetails.GetPaymentDestination(),
                BtcDue              = accounting.Due.ToString(),
                OrderAmount         = (accounting.TotalDue - accounting.NetworkFee).ToString(),
                OrderAmountFiat     = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation),
                CustomerEmail       = invoice.RefundMail,
                RequiresRefundEmail = storeBlob.RequiresRefundEmail,
                ExpirationSeconds   = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
                MaxTimeSeconds      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
                MaxTimeMinutes      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
                ItemDesc            = invoice.ProductInformation.ItemDesc,
                Rate                  = ExchangeRate(paymentMethod),
                MerchantRefLink       = invoice.RedirectURL ?? "/",
                RedirectAutomatically = invoice.RedirectAutomatically,
                StoreName             = store.StoreName,
                PeerInfo              = (paymentMethodDetails as LightningLikePaymentMethodDetails)?.NodeInfo,
                TxCount               = accounting.TxRequired,
                BtcPaid               = accounting.Paid.ToString(),
#pragma warning disable CS0618 // Type or member is obsolete
                Status = invoice.StatusString,
#pragma warning restore CS0618 // Type or member is obsolete
                NetworkFee          = paymentMethodDetails.GetNextNetworkFee(),
                IsMultiCurrency     = invoice.GetPayments().Select(p => p.GetPaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1,
                ChangellyEnabled    = changelly != null,
                ChangellyMerchantId = changelly?.ChangellyMerchantId,
                ChangellyAmountDue  = changellyAmountDue,
                CoinSwitchEnabled   = coinswitch != null,
                CoinSwitchAmountMarkupPercentage = coinswitch?.AmountMarkupPercentage ?? 0,
                CoinSwitchMerchantId             = coinswitch?.MerchantId,
                CoinSwitchMode   = coinswitch?.Mode,
                StoreId          = store.Id,
                AvailableCryptos = invoice.GetPaymentMethods()
                                   .Where(i => i.Network != null)
                                   .Select(kv =>
                {
                    var availableCryptoPaymentMethodId = kv.GetId();
                    var availableCryptoHandler         = _paymentMethodHandlerDictionary[availableCryptoPaymentMethodId];
                    return(new PaymentModel.AvailableCrypto()
                    {
                        PaymentMethodId = kv.GetId().ToString(),
                        CryptoCode = kv.GetId().CryptoCode,
                        PaymentMethodName = availableCryptoHandler.GetPaymentMethodName(availableCryptoPaymentMethodId),
                        IsLightning =
                            kv.GetId().PaymentType == PaymentTypes.LightningLike,
                        CryptoImage = Request.GetRelativePathOrAbsolute(availableCryptoHandler.GetCryptoImage(availableCryptoPaymentMethodId)),
                        Link = Url.Action(nameof(Checkout),
                                          new
                        {
                            invoiceId = invoiceId,
                            paymentMethodId = kv.GetId().ToString()
                        })
                    });
                }).Where(c => c.CryptoImage != "/")
                                   .OrderByDescending(a => a.CryptoCode == "BTC").ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0)
                                   .ToList()
            };

            paymentMethodHandler.PreparePaymentModel(model, dto);
            model.PaymentMethodId = paymentMethodId.ToString();
            var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);

            model.TimeLeft = expiration.PrettyPrint();
            return(model);
        }
Beispiel #6
0
        /// <summary>
        /// Add a payment to an invoice
        /// </summary>
        /// <param name="invoiceId"></param>
        /// <param name="date"></param>
        /// <param name="paymentData"></param>
        /// <param name="cryptoCode"></param>
        /// <param name="accounted"></param>
        /// <returns>The PaymentEntity or null if already added</returns>
        public async Task <PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, BTCPayNetworkBase network, bool accounted = false)
        {
            using (var context = _ContextFactory.CreateContext())
            {
                var invoice = context.Invoices.Find(invoiceId);
                if (invoice == null)
                {
                    return(null);
                }
                InvoiceEntity         invoiceEntity        = ToObject(invoice.Blob);
                PaymentMethod         paymentMethod        = invoiceEntity.GetPaymentMethod(new PaymentMethodId(network.CryptoCode, paymentData.GetPaymentType()));
                IPaymentMethodDetails paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
                PaymentEntity         entity = new PaymentEntity
                {
                    Version = 1,
#pragma warning disable CS0618
                    CryptoCode = network.CryptoCode,
#pragma warning restore CS0618
                    ReceivedTime = date.UtcDateTime,
                    Accounted    = accounted,
                    NetworkFee   = paymentMethodDetails.GetNextNetworkFee(),
                    Network      = network
                };
                entity.SetCryptoPaymentData(paymentData);
                //TODO: abstract
                if (paymentMethodDetails is Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod bitcoinPaymentMethod &&
                    bitcoinPaymentMethod.NetworkFeeMode == NetworkFeeMode.MultiplePaymentsOnly &&
                    bitcoinPaymentMethod.NextNetworkFee == Money.Zero)
                {
                    bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes
                    paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod);
                    invoiceEntity.SetPaymentMethod(paymentMethod);
                    invoice.Blob = ToBytes(invoiceEntity, network);
                }
                PaymentData data = new PaymentData
                {
                    Id            = paymentData.GetPaymentId(),
                    Blob          = ToBytes(entity, entity.Network),
                    InvoiceDataId = invoiceId,
                    Accounted     = accounted
                };

                context.Payments.Add(data);

                try
                {
                    await context.SaveChangesAsync().ConfigureAwait(false);
                }
                catch (DbUpdateException) { return(null); } // Already exists
                AddToTextSearch(invoiceId, paymentData.GetSearchTerms());
                return(entity);
            }
        }
 public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)
 {
     return(JsonConvert.SerializeObject(paymentData));
 }
Beispiel #8
0
 private string GetCryptoImage(BTCPayNetworkBase network)
 {
     return(network.CryptoImagePath);
 }
Beispiel #9
0
 public abstract string GetTransactionLink(BTCPayNetworkBase network, string txId);
 public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
 {
     return(JsonConvert.DeserializeObject <MoneroLikePaymentData>(str));
 }
Beispiel #11
0
 public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value);
Beispiel #12
0
 public abstract string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details);
Beispiel #13
0
 public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str);
 public override string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details)
 {
     return(((BTCPayNetwork)network).ToString((BitcoinLikeOnChainPaymentMethod)details));
 }
 public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str)
 {
     return(JsonConvert.DeserializeObject <MoneroLikeOnChainPaymentMethodDetails>(str));
 }
        private async Task <PaymentMethod?> CreatePaymentMethodAsync(
            Dictionary <CurrencyPair, Task <RateResult> > fetchingByCurrencyPair,
            IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetworkBase network,
            InvoiceEntity entity,
            StoreData store, InvoiceLogs logs,
            HashSet <PaymentMethodId> invoicePaymentMethods)
        {
            try
            {
                var logPrefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:";
                var storeBlob = store.GetStoreBlob();

                object?preparePayment;
                if (storeBlob.LazyPaymentMethods)
                {
                    preparePayment = null;
                }
                else
                {
                    preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network);
                }
                var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.Currency)];
                if (rate.BidAsk == null)
                {
                    return(null);
                }
                var paymentMethod = new PaymentMethod
                {
                    ParentEntity = entity,
                    Network      = network,
                    Rate         = rate.BidAsk.Bid,
                    PreferOnion  = Uri.TryCreate(entity.ServerUrl, UriKind.Absolute, out var u) && u.DnsSafeHost.EndsWith(".onion", StringComparison.OrdinalIgnoreCase)
                };
                paymentMethod.SetId(supportedPaymentMethod.PaymentId);

                using (logs.Measure($"{logPrefix} Payment method details creation"))
                {
                    var paymentDetails = await handler.CreatePaymentMethodDetails(logs, supportedPaymentMethod, paymentMethod, store, network, preparePayment, invoicePaymentMethods);

                    paymentMethod.SetPaymentMethodDetails(paymentDetails);
                }

                var criteria = storeBlob.PaymentMethodCriteria?.Find(methodCriteria => methodCriteria.PaymentMethod == supportedPaymentMethod.PaymentId);
                if (criteria?.Value != null && entity.Type != InvoiceType.TopUp)
                {
                    var currentRateToCrypto =
                        await fetchingByCurrencyPair[new CurrencyPair(supportedPaymentMethod.PaymentId.CryptoCode, criteria.Value.Currency)];
                    if (currentRateToCrypto?.BidAsk != null)
                    {
                        var amount           = paymentMethod.Calculate().Due.GetValue(network as BTCPayNetwork);
                        var limitValueCrypto = criteria.Value.Value / currentRateToCrypto.BidAsk.Bid;

                        if (amount < limitValueCrypto && criteria.Above)
                        {
                            logs.Write($"{logPrefix} invoice amount below accepted value for payment method", InvoiceEventData.EventSeverity.Error);
                            return(null);
                        }
                        if (amount > limitValueCrypto && !criteria.Above)
                        {
                            logs.Write($"{logPrefix} invoice amount above accepted value for payment method", InvoiceEventData.EventSeverity.Error);
                            return(null);
                        }
                    }
                    else
                    {
                        var suffix = currentRateToCrypto?.EvaluatedRule is string s ? $" ({s})" : string.Empty;
                        logs.Write($"{logPrefix} This payment method should be created only if the amount of this invoice is in proper range. However, we are unable to fetch the rate of those limits. {suffix}", InvoiceEventData.EventSeverity.Warning);
                    }
                }

#pragma warning disable CS0618
                if (paymentMethod.GetId().IsBTCOnChain)
                {
                    entity.TxFee          = paymentMethod.NextNetworkFee;
                    entity.Rate           = paymentMethod.Rate;
                    entity.DepositAddress = paymentMethod.DepositAddress;
                }
#pragma warning restore CS0618
                return(paymentMethod);
            }
            catch (PaymentMethodUnavailableException ex)
            {
                logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error);
            }
            catch (Exception ex)
            {
                logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex})", InvoiceEventData.EventSeverity.Error);
            }
            return(null);
        }
 public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value)
 {
     return(JsonConvert.DeserializeObject <MoneroSupportedPaymentMethod>(value.ToString()));
 }
Beispiel #18
0
 private string GetPaymentMethodName(BTCPayNetworkBase network)
 {
     return(network.DisplayName);
 }
 public override string GetTransactionLink(BTCPayNetworkBase network, string txId)
 {
     return(string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId));
 }
Beispiel #20
0
        public async Task <bool> NewAddress(string invoiceId, IPaymentMethodDetails paymentMethod, BTCPayNetworkBase network)
        {
            using (var context = _ContextFactory.CreateContext())
            {
                var invoice = (await context.Invoices.Where(i => i.Id == invoiceId).ToListAsync()).FirstOrDefault();
                if (invoice == null)
                {
                    return(false);
                }

                var invoiceEntity = ToObject(invoice.Blob);
                var currencyData  = invoiceEntity.GetPaymentMethod(network, paymentMethod.GetPaymentType());
                if (currencyData == null)
                {
                    return(false);
                }

                var existingPaymentMethod = currencyData.GetPaymentMethodDetails();
                if (existingPaymentMethod.GetPaymentDestination() != null)
                {
                    MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId());
                }

                existingPaymentMethod.SetPaymentDestination(paymentMethod.GetPaymentDestination());
                currencyData.SetPaymentMethodDetails(existingPaymentMethod);
#pragma warning disable CS0618
                if (network.IsBTC)
                {
                    invoiceEntity.DepositAddress = currencyData.DepositAddress;
                }
#pragma warning restore CS0618
                invoiceEntity.SetPaymentMethod(currencyData);
                invoice.Blob = ToBytes(invoiceEntity, network);

                context.AddressInvoices.Add(new AddressInvoiceData()
                {
                    InvoiceDataId = invoiceId,
                    CreatedTime   = DateTimeOffset.UtcNow
                }
                                            .Set(GetDestination(currencyData), currencyData.GetId()));
                context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
                {
                    InvoiceDataId = invoiceId,
                    Assigned      = DateTimeOffset.UtcNow
                }.SetAddress(paymentMethod.GetPaymentDestination(), network.CryptoCode));

                await context.SaveChangesAsync();

                AddToTextSearch(invoice.Id, paymentMethod.GetPaymentDestination());
                return(true);
            }
        }
 public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails, Money cryptoInfoDue, string serverUri)
 {
     return
         ($"{(network as MoneroLikeSpecificBtcPayNetwork).UriScheme}:{paymentMethodDetails.GetPaymentDestination()}?tx_amount={cryptoInfoDue.ToDecimal(MoneyUnit.BTC)}");
 }
Beispiel #22
0
 private byte[] ToBytes <T>(T obj, BTCPayNetworkBase network = null)
 {
     return(ZipUtils.Zip(ToString(obj, network)));
 }
Beispiel #23
0
 public BTCPayWallet GetWallet(BTCPayNetworkBase network)
 {
     ArgumentNullException.ThrowIfNull(network);
     return(GetWallet(network.CryptoCode));
 }
Beispiel #24
0
 public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)
 {
     return(((BTCPayNetwork)network).ToString(paymentData));
 }
Beispiel #25
0
 public bool IsAvailable(BTCPayNetworkBase network)
 {
     return(_Client.IsAvailable(network));
 }
Beispiel #26
0
 public override string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details)
 {
     return(JsonConvert.SerializeObject(details));
 }
Beispiel #27
0
 public abstract CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str);