Exemplo n.º 1
0
        public async Task <LightningInvoice> GetInvoice(string invoiceId,
                                                        CancellationToken cancellation = default(CancellationToken))
        {
            InvoiceResponse result = null;

            try
            {
                result = await _eclairClient.GetInvoice(invoiceId, cancellation);
            }
            catch (EclairClient.EclairApiException ex) when(ex.Error.Error == "Not found" || ex.Error.Error.Contains("Invalid hexadecimal", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            GetReceivedInfoResponse info = null;

            try
            {
                info = await _eclairClient.GetReceivedInfo(invoiceId, null, cancellation);
            }
            catch (EclairClient.EclairApiException)
            {
            }

            var parsed    = BOLT11PaymentRequest.Parse(result.Serialized, _network);
            var lnInvoice = new LightningInvoice()
            {
                Id        = result.PaymentHash,
                Amount    = parsed.MinimumAmount,
                ExpiresAt = parsed.ExpiryDate,
                BOLT11    = result.Serialized
            };

            if (DateTimeOffset.UtcNow >= parsed.ExpiryDate)
            {
                lnInvoice.Status = LightningInvoiceStatus.Expired;
            }
            if (info != null && info.Status.Type == "received")
            {
                lnInvoice.AmountReceived = info.Status.Amount;
                lnInvoice.Status         = info.Status.Amount >= parsed.MinimumAmount ? LightningInvoiceStatus.Paid : LightningInvoiceStatus.Unpaid;
                lnInvoice.PaidAt         = info.Status.ReceivedAt;
            }
            return(lnInvoice);
        }
Exemplo n.º 2
0
        public async Task CanCreateInvoiceWithDescriptionHash()
        {
            var hashToUse =
                new uint256(new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes("CanCreateInvoiceWithDescriptionHash")));

            async Task <LightningInvoice> CreateWithHash(ILightningClient lightningClient)
            {
                return(await lightningClient.CreateInvoice(new CreateInvoiceParams(10000, hashToUse,
                                                                                   TimeSpan.FromMinutes(5))));
            }

            await WaitServersAreUp();

            foreach (var client in Tester.GetLightningClients())
            {
                switch (client.Client)
                {
                case CLightningClient _:
                case LndClient _:
                    Logs.Tester.LogInformation($"{client.Name}: {nameof(CanCreateInvoiceWithDescriptionHash)}");
                    var createdInvoice = await CreateWithHash(client.Client);

                    var retrievedInvoice = await client.Client.GetInvoice(createdInvoice.Id);

                    Logs.Tester.LogInformation(JObject.FromObject(createdInvoice).ToString());
                    Logs.Tester.LogInformation(JObject.FromObject(retrievedInvoice).ToString());
                    AssertUnpaid(createdInvoice);
                    AssertUnpaid(retrievedInvoice);
                    var createdInvoiceBOLT    = BOLT11PaymentRequest.Parse(createdInvoice.BOLT11, Network.RegTest);
                    var retrievedInvoiceeBOLT = BOLT11PaymentRequest.Parse(retrievedInvoice.BOLT11, Network.RegTest);
                    Assert.Equal(createdInvoiceBOLT.PaymentHash, retrievedInvoiceeBOLT.PaymentHash);
                    Assert.Equal(hashToUse, createdInvoiceBOLT.DescriptionHash);
                    break;

                default:
                    await Assert.ThrowsAsync <NotSupportedException>(async() =>
                    {
                        await CreateWithHash(client.Client);
                    });

                    break;
                }
            }
        }
Exemplo n.º 3
0
        public async Task <LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry,
                                                           CancellationToken cancellation = default(CancellationToken))
        {
            var result = await _eclairClient.CreateInvoice(
                description,
                amount.MilliSatoshi,
                Convert.ToInt32(expiry.TotalSeconds), null, cancellation);

            var parsed  = BOLT11PaymentRequest.Parse(result.Serialized, _network);
            var invoice = new LightningInvoice()
            {
                BOLT11    = result.Serialized,
                Amount    = amount,
                Id        = result.PaymentHash,
                Status    = LightningInvoiceStatus.Unpaid,
                ExpiresAt = parsed.ExpiryDate
            };

            return(invoice);
        }
        internal LightningInvoice GetLightningInvoiceObject(ListInvoiceResultResponse invoice, Network network)
        {
            var parsed = BOLT11PaymentRequest.Parse(invoice.Bolt11, network);

            var lightningInvoice = new LightningInvoice()
            {
                Id             = invoice.Hash,
                Amount         = invoice.AmountMsat,
                AmountReceived = invoice.AmountMsat,
                BOLT11         = invoice.Bolt11,
                Status         = ToStatus(invoice.State),
                PaidAt         = null,
                ExpiresAt      = parsed.ExpiryDate
            };

            if (invoice.State == "used")
            {
                lightningInvoice.PaidAt = parsed.ExpiryDate;
            }

            return(lightningInvoice);
        }
Exemplo n.º 5
0
        public async Task <LightningInvoice> GetInvoice(string invoiceId,
                                                        CancellationToken cancellation = default(CancellationToken))
        {
            var result = await _eclairClient.GetInvoice(invoiceId, cancellation);

            GetReceivedInfoResponse info;

            try
            {
                info = await _eclairClient.GetReceivedInfo(invoiceId, null, cancellation);
            }
            catch (EclairClient.EclairApiException)
            {
                info = new GetReceivedInfoResponse()
                {
                    AmountMsat  = 0,
                    ReceivedAt  = 0,
                    PaymentHash = invoiceId
                };
            }

            var parsed = BOLT11PaymentRequest.Parse(result.Serialized, _network);

            return(new LightningInvoice()
            {
                Id = result.PaymentHash,
                Amount = parsed.MinimumAmount,
                ExpiresAt = parsed.ExpiryDate,
                BOLT11 = result.Serialized,
                AmountReceived = info.AmountMsat,
                Status = info.AmountMsat >= parsed.MinimumAmount ? LightningInvoiceStatus.Paid :
                         DateTime.Now >= parsed.ExpiryDate ? LightningInvoiceStatus.Expired : LightningInvoiceStatus.Unpaid,
                PaidAt = info.ReceivedAt == 0
                    ? (DateTimeOffset?)null
                    : DateTimeOffset.FromUnixTimeMilliseconds(info.ReceivedAt)
            });
        }
        public async Task <LightningInvoice> GetInvoice(string invoiceId,
                                                        CancellationToken cancellation = default(CancellationToken))
        {
            var result = await _eclairClient.GetInvoice(invoiceId, cancellation);

            GetReceivedInfoResponse info = null;

            try
            {
                info = await _eclairClient.GetReceivedInfo(invoiceId, null, cancellation);
            }
            catch (EclairClient.EclairApiException)
            {
            }

            var parsed    = BOLT11PaymentRequest.Parse(result.Serialized, _network);
            var lnInvoice = new LightningInvoice()
            {
                Id        = result.PaymentHash,
                Amount    = parsed.MinimumAmount,
                ExpiresAt = parsed.ExpiryDate,
                BOLT11    = result.Serialized
            };

            if (DateTimeOffset.UtcNow >= parsed.ExpiryDate)
            {
                lnInvoice.Status = LightningInvoiceStatus.Expired;
            }
            if (info != null && info.Status.Type == "received")
            {
                lnInvoice.AmountReceived = info.Status.Amount;
                lnInvoice.Status         = info.Status.Amount >= parsed.MinimumAmount ? LightningInvoiceStatus.Paid : LightningInvoiceStatus.Unpaid;
                lnInvoice.PaidAt         = info.Status.ReceivedAt;
            }
            return(lnInvoice);
        }
 public uint256 GetPaymentHash(Network network)
 {
     return(PaymentHash ?? BOLT11PaymentRequest.Parse(BOLT11, network).PaymentHash);
 }
Exemplo n.º 8
0
        public override async Task <IPaymentMethodDetails> CreatePaymentMethodDetails(
            InvoiceLogs logs,
            LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, Data.StoreData store,
            BTCPayNetwork network, object preparePaymentObject)
        {
            if (paymentMethod.ParentEntity.Type == InvoiceType.TopUp)
            {
                throw new PaymentMethodUnavailableException("Lightning Network payment method is not available for top-up invoices");
            }

            if (preparePaymentObject is null)
            {
                return(new LightningLikePaymentMethodDetails()
                {
                    Activated = false
                });
            }
            //direct casting to (BTCPayNetwork) is fixed in other pull requests with better generic interfacing for handlers
            var storeBlob = store.GetStoreBlob();
            var test      = GetNodeInfo(supportedPaymentMethod, network, paymentMethod.PreferOnion);

            var     invoice = paymentMethod.ParentEntity;
            decimal due     = Extensions.RoundUp(invoice.Price / paymentMethod.Rate, network.Divisibility);

            try
            {
                due = paymentMethod.Calculate().Due.ToDecimal(MoneyUnit.BTC);
            }
            catch (Exception)
            {
                // ignored
            }
            var client = supportedPaymentMethod.CreateLightningClient(network, Options.Value, _lightningClientFactory);
            var expiry = invoice.ExpirationTime - DateTimeOffset.UtcNow;

            if (expiry < TimeSpan.Zero)
            {
                expiry = TimeSpan.FromSeconds(1);
            }

            LightningInvoice?lightningInvoice = null;

            string description = storeBlob.LightningDescriptionTemplate;

            description = description.Replace("{StoreName}", store.StoreName ?? "", StringComparison.OrdinalIgnoreCase)
                          .Replace("{ItemDescription}", invoice.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase)
                          .Replace("{OrderId}", invoice.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase);
            using (var cts = new CancellationTokenSource(LIGHTNING_TIMEOUT))
            {
                try
                {
                    var request = new CreateInvoiceParams(new LightMoney(due, LightMoneyUnit.BTC), description, expiry);
                    request.PrivateRouteHints = storeBlob.LightningPrivateRouteHints;
                    lightningInvoice          = await client.CreateInvoice(request, cts.Token);
                }
                catch (OperationCanceledException) when(cts.IsCancellationRequested)
                {
                    throw new PaymentMethodUnavailableException("The lightning node did not reply in a timely manner");
                }
                catch (Exception ex)
                {
                    throw new PaymentMethodUnavailableException($"Impossible to create lightning invoice ({ex.Message})", ex);
                }
            }

            var nodeInfo = await test;

            return(new LightningLikePaymentMethodDetails
            {
                Activated = true,
                BOLT11 = lightningInvoice.BOLT11,
                PaymentHash = BOLT11PaymentRequest.Parse(lightningInvoice.BOLT11, network.NBitcoinNetwork).PaymentHash,
                InvoiceId = lightningInvoice.Id,
                NodeInfo = nodeInfo.First().ToString()
            });
        }
Exemplo n.º 9
0
 public BoltInvoiceClaimDestination(string bolt11, Network network)
 {
     _bolt11 = bolt11 ?? throw new ArgumentNullException(nameof(bolt11));
     _amount = BOLT11PaymentRequest.Parse(bolt11, network).MinimumAmount.ToDecimal(LightMoneyUnit.BTC);
 }
 public BOLT11PaymentRequest ParsePaymentRequest(string payReq)
 {
     return(BOLT11PaymentRequest.Parse(payReq, _network));
 }