Example #1
0
        public async Task <IActionResult> OnPostAsync(string walletId)
        {
            Wallet = await _walletService.GetWallet(new WalletQuery {
                UserId              = UserId,
                WalletId            = walletId,
                IncludeTransactions = true
            });

            if (Wallet == null)
            {
                return(NotFound());
            }
            if (!ModelState.IsValid)
            {
                return(Page());
            }

            try
            {
                var amount      = LightMoney.Satoshis(Amount).MilliSatoshi;
                var transaction = await _walletService.Receive(Wallet, amount, Description);

                var transactionId = transaction.TransactionId;
                return(RedirectToPage("/Transactions/Details", new { walletId, transactionId }));
            }
            catch (Exception exception)
            {
                _logger.LogError($"Receiving failed! {exception}");
                ErrorMessage = exception.Message;
            }

            return(Page());
        }
Example #2
0
        public async Task CanHandleSelfPayment()
        {
            await WaitServersAreUp();

            foreach (var client in Tester.GetLightningClients())
            {
                Logs.Tester.LogInformation($"{client.Name}: {nameof(CanHandleSelfPayment)}");

                var expiry  = TimeSpan.FromSeconds(5000);
                var amount  = LightMoney.Satoshis(21);
                var invoice = await client.Client.CreateInvoice(amount, "CanHandleSelfPayment", expiry);

                switch (client.Client)
                {
                case LndClient _:
                case CLightningClient _:
                case EclairLightningClient _:
                    var response = await client.Client.Pay(invoice.BOLT11);

                    Assert.Equal(PayResult.CouldNotFindRoute, response.Result);
                    break;

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

                    break;
                }
            }
        }
        protected override async Task <TypedActionHandlerResult <LightningInvoice> > Execute(Dictionary <string, object> data, RecipeAction recipeAction,
                                                                                             CreateBolt11InvoiceData actionData)
        {
            using (var serviceScope = DependencyHelper.ServiceScopeFactory.CreateScope())
            {
                var externalService = await recipeAction.GetExternalService();

                var service = new LightningNodeService(externalService,
                                                       serviceScope.ServiceProvider.GetService <NBXplorerClientProvider>(),
                                                       serviceScope.ServiceProvider.GetService <NBXplorerSummaryProvider>(),
                                                       serviceScope.ServiceProvider.GetService <SocketFactory>()
                                                       );

                var client  = service.ConstructClient();
                var invoice = await client.CreateInvoice(
                    LightMoney.FromUnit(decimal.Parse(InterpolateString(actionData.Amount, data)),
                                        actionData.AmountMoneyUnit),
                    InterpolateString(actionData.Description, data),
                    TimeSpan.FromMilliseconds(int.Parse(InterpolateString(actionData.ExpiryMilliseconds, data))));

                return(new TypedActionHandlerResult <LightningInvoice>()
                {
                    Executed = true,
                    Result =
                        $"Created Bolt11 invoice {invoice.BOLT11}",
                    TypedData = invoice
                });
            }
        }
        public void CanSerializeDeserializeLightMoney()
        {
            var converter = new LightMoneyJsonConverter();
            var lm        = new LightMoney(100);
            var json      = JsonConvert.SerializeObject(lm, converter);

            Assert.Equal(lm.MilliSatoshi, JsonConvert.DeserializeObject <LightMoney>(json, converter).MilliSatoshi);
        }
Example #5
0
        public void CanUseLightMoney()
        {
            var light = LightMoney.MilliSatoshis(1);

            Assert.Equal("0.00000000001", light.ToString());

            light = LightMoney.MilliSatoshis(200000);
            Assert.Equal(200m, light.ToDecimal(LightMoneyUnit.Satoshi));
            Assert.Equal(0.00000001m * 200m, light.ToDecimal(LightMoneyUnit.BTC));
        }
Example #6
0
        async Task <LightningInvoice> ILightningClient.CreateInvoice(LightMoney amount, string description, TimeSpan expiry, CancellationToken cancellation)
        {
            var id      = InvoiceIdEncoder.EncodeData(RandomUtils.GetBytes(20));
            var invoice = await SendCommandAsync <CLightningInvoice>("invoice", new object[] { amount.MilliSatoshi, id, description ?? "", Math.Max(0, (int)expiry.TotalSeconds) }, cancellation : cancellation);

            invoice.Label        = id;
            invoice.MilliSatoshi = amount;
            invoice.Status       = "unpaid";
            return(ToLightningInvoice(invoice));
        }
Example #7
0
        async Task <LightningInvoice> ILightningInvoiceClient.CreateInvoice(LightMoney amount, TimeSpan expiry, CancellationToken cancellation)
        {
            var id      = InvoiceIdEncoder.EncodeData(RandomUtils.GetBytes(20));
            var invoice = await SendCommandAsync <CreateInvoiceResponse>("invoice", new object[] { amount.MilliSatoshi, id, "" }, cancellation : cancellation);

            invoice.Label        = id;
            invoice.MilliSatoshi = amount;
            invoice.Status       = "unpaid";
            return(ToLightningInvoice(invoice));
        }
Example #8
0
        async Task <LightningInvoice> ILightningClient.CreateInvoice(LightMoney amount, string description, TimeSpan expiry, CancellationToken cancellation)
        {
            var invoice = await CreateInvoiceAsync(new CreateInvoiceRequest()
            {
                Amount = amount, Expiry = expiry, Description = description ?? ""
            }, cancellation);

            return(new LightningInvoice()
            {
                Id = invoice.Id, Amount = amount, BOLT11 = invoice.PayReq, Status = LightningInvoiceStatus.Unpaid, ExpiresAt = DateTimeOffset.UtcNow + expiry
            });
        }
        async Task <LightningInvoice> ILightningInvoiceClient.CreateInvoice(LightMoney amount, TimeSpan expiry, CancellationToken cancellation)
        {
            var invoice = await CreateInvoiceAsync(new CreateInvoiceRequest()
            {
                Amont = amount, Expiry = expiry
            });

            return(new LightningInvoice()
            {
                Id = invoice.Id, Amount = amount, BOLT11 = invoice.PayReq, Status = "unpaid"
            });
        }
Example #10
0
 //[Benchmark]
 public async Task RunAlicePaysBobViaCarol()
 {
     int paymentsLeft = TotalPayments;
     await Task.WhenAll(Enumerable.Range(0, Concurrency)
                        .Select(async _ =>
     {
         while (Interlocked.Decrement(ref paymentsLeft) >= 0)
         {
             var invoice = await Bob.GetRPC(_).CreateInvoice(LightMoney.Satoshis(100));
             await Alice.GetRPC(_).SendAsync(invoice.BOLT11);
         }
     }));
 }
        public async Task CanPayInvoiceAndReceive()
        {
            foreach (var test in Tester.GetTestedPairs())
            {
                await EnsureConnectedToDestinations(test);

                Logs.Tester.LogInformation($"{test.Name}: {nameof(CanPayInvoiceAndReceive)}");
                var amount  = LightMoney.Satoshis(1000);
                var invoice = await test.Merchant.CreateInvoice(amount, "CanPayInvoiceAndReceive", TimeSpan.FromSeconds(5000));

                using (var listener = await test.Merchant.Listen())
                {
                    var waiting   = listener.WaitInvoice(default);
        public async Task <string> ReceiveAsync(LightMoney amount, string description = null)
        {
            if (amount == null)
            {
                throw new ArgumentNullException(nameof(amount));
            }
            List <object> args = new List <object>();

            args.Add(amount.MilliSatoshi);
            if (description != null)
            {
                args.Add(description);
            }
            return((await SendCommandAsync(new RPCRequest("receive", args.ToArray())).ConfigureAwait(false)).ResultString);
        }
        public async Task <string> OpenAsync(NodeInfo node, Money fundingSatoshi, LightMoney pushAmount = null)
        {
            if (fundingSatoshi == null)
            {
                throw new ArgumentNullException(nameof(fundingSatoshi));
            }
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            pushAmount = pushAmount ?? LightMoney.Zero;

            var result = await SendCommandAsync(new RPCRequest("open", new object[] { node.NodeId, fundingSatoshi.Satoshi, pushAmount.MilliSatoshi }));

            return(result.ResultString);
        }
Example #14
0
        public static async Task <(BOLT11PaymentRequest, ResultVM)> GetInvoiceFromLNURL(PayoutData payoutData,
                                                                                        LightningLikePayoutHandler handler, PayoutBlob blob, LNURLPayClaimDestinaton lnurlPayClaimDestinaton, Network network)
        {
            var endpoint = lnurlPayClaimDestinaton.LNURL.IsValidEmail()
                ? LNURL.LNURL.ExtractUriFromInternetIdentifier(lnurlPayClaimDestinaton.LNURL)
                : LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out _);
            var httpClient = handler.CreateClient(endpoint);
            var lnurlInfo  =
                (LNURLPayRequest)await LNURL.LNURL.FetchInformation(endpoint, "payRequest",
                                                                    httpClient);

            var lm = new LightMoney(blob.CryptoAmount.Value, LightMoneyUnit.BTC);

            if (lm > lnurlInfo.MaxSendable || lm < lnurlInfo.MinSendable)
            {
                return(null, new ResultVM
                {
                    PayoutId = payoutData.Id,
                    Result = PayResult.Error,
                    Destination = blob.Destination,
                    Message =
                        $"The LNURL provided would not generate an invoice of {lm.MilliSatoshi}msats"
                });
            }

            try
            {
                var lnurlPayRequestCallbackResponse =
                    await lnurlInfo.SendRequest(lm, network, httpClient);

                return(lnurlPayRequestCallbackResponse.GetPaymentRequest(network), null);
            }
            catch (LNUrlException e)
            {
                return(null,
                       new ResultVM
                {
                    PayoutId = payoutData.Id,
                    Result = PayResult.Error,
                    Destination = blob.Destination,
                    Message = e.Message
                });
            }
        }
        private async Task MarkTransactionPaid(Transaction transaction, LightMoney amountSettled, DateTimeOffset?date)
        {
            _logger.LogInformation($"Marking transaction {transaction.TransactionId} as paid.");

            transaction.AmountSettled = amountSettled;
            transaction.PaidAt        = date;

            await UpdateTransaction(transaction);

            await _transactionHub.Clients.All.SendAsync("transaction-update", new
            {
                transaction.TransactionId,
                transaction.InvoiceId,
                transaction.WalletId,
                transaction.Status,
                transaction.IsPaid,
                transaction.IsExpired,
                Event = "paid"
            });
        }
Example #16
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);
        }
        public override void PreparePaymentModel(PaymentModel model, InvoiceResponse invoiceResponse, StoreBlob storeBlob)
        {
            var paymentMethodId = new PaymentMethodId(model.CryptoCode, PaymentType);

            var client = _moneroRpcProvider.WalletRpcClients[model.CryptoCode];

            var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
            var network    = _networkProvider.GetNetwork <MoneroLikeSpecificBtcPayNetwork>(model.CryptoCode);

            model.IsLightning       = false;
            model.PaymentMethodName = GetPaymentMethodName(network);
            model.CryptoImage       = GetCryptoImage(network);
            model.InvoiceBitcoinUrl = client.SendCommandAsync <MakeUriRequest, MakeUriResponse>("make_uri", new MakeUriRequest()
            {
                Address = cryptoInfo.Address,
                Amount  = LightMoney.Parse(cryptoInfo.Due).MilliSatoshi
            }).GetAwaiter()
                                      .GetResult().Uri;
            model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
        }
        public async Task WaitRouteTo(ActorTester destination)
        {
            var info = await destination.RPC.GetInfoAsync();

            int blockToMine = 6;

            while (true)
            {
                var route = await RPC.GetRouteAsync(info.Id, LightMoney.Satoshis(100), 0.0);

                if (route != null)
                {
                    break;
                }
                await Task.Delay(1000);

                BitcoinRPC.Generate(blockToMine);
                blockToMine = 1;
            }
            Console.WriteLine($"// Route from {this.P2PHost} to {destination.P2PHost} can now be used");
        }
Example #19
0
        public async void ShouldStartNodesAndPrepare()
        {
            using (var builder = LightningNodeLauncher.lnLauncher.createBuilder("Test1"))
            {
                builder.startNode();
                builder.ConnectAll();
                var clients = builder.GetClients();
                builder.PrepareLNFunds(Money.Coins(10m));
                builder.OpenChannel(clients.Bitcoin, clients.Rebalancer, clients.ThirdParty, Money.Satoshis(500000m));
                builder.OpenChannel(clients.Bitcoin, clients.Custody, clients.ThirdParty, Money.Satoshis(500000m));

                var destInfo = await clients.Custody.GetInfo();

                var routeResp = await clients.Rebalancer.SwaggerClient.QueryRoutesAsync(destInfo.NodeInfo.NodeId.ToHex(), "1000", 1);

                Assert.NotNull(routeResp.Routes);
                Assert.NotEmpty(routeResp.Routes);

                var destInvoice = await clients.Custody.CreateInvoice(LightMoney.Satoshis(1000), "UnitTest1", TimeSpan.FromMinutes(5.0));
            }
        }
Example #20
0
        public async Task CanPayInvoiceAndReceive()
        {
            foreach (var test in Tester.GetTestedPairs())
            {
                Logs.Tester.LogInformation($"{test.Name}: {nameof(CanPayInvoiceAndReceive)}");
                await EnsureConnectedToDestinations(test);

                var expiry  = TimeSpan.FromSeconds(5000);
                var amount  = LightMoney.Satoshis(21);
                var invoice = await test.Merchant.CreateInvoice(amount, "CanPayInvoiceAndReceive", expiry);

                var invoiceMaxFeePercent = await test.Merchant.CreateInvoice(amount, "CanPayInvoiceWithMaxFeeAndReceivePercent", expiry);

                var invoiceMaxFeePercent2 = await test.Merchant.CreateInvoice(amount, "CanPayInvoiceWithMaxFeeAndReceivePercent2", expiry);

                var invoiceMaxFeeLimit = await test.Merchant.CreateInvoice(amount, "CanPayInvoiceWithMaxFeeAndReceiveLimit", expiry);

                var invoiceZeroAmount = await test.Merchant.CreateInvoice(LightMoney.Zero, "CanPayInvoiceWithZeroAmount", expiry);

                using var listener = await test.Merchant.Listen();

                var waiting   = listener.WaitInvoice(default);
Example #21
0
        public async Task <LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry,
                                                           CancellationToken cancellation = default(CancellationToken))
        {
            var strAmount = ConvertInv.ToString(amount.ToUnit(LightMoneyUnit.Satoshi));
            var strExpiry = ConvertInv.ToString(Math.Round(expiry.TotalSeconds, 0));
            // lnd requires numbers sent as strings. don't ask
            var resp = await _rpcClient.AddInvoiceAsync(new LnrpcInvoice
            {
                Value  = strAmount,
                Memo   = description,
                Expiry = strExpiry
            });

            var invoice = new LightningInvoice
            {
                Id     = BitString(resp.R_hash),
                Amount = amount,
                BOLT11 = resp.Payment_request,
                Status = "unpaid"
            };

            return(invoice);
        }
Example #22
0
        public async Task CanCreateInvoice()
        {
            await WaitServersAreUp();

            foreach (var client in Tester.GetLightningClients())
            {
                Logs.Tester.LogInformation($"{client.Name}: {nameof(CanCreateInvoice)}");
                var createdInvoice = await client.Client.CreateInvoice(10001, "CanCreateInvoice", TimeSpan.FromMinutes(5));

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

                AssertUnpaid(createdInvoice, LightMoney.MilliSatoshis(10001));
                Assert.True(createdInvoice.ExpiresAt > DateTimeOffset.UtcNow);
                AssertUnpaid(retrievedInvoice, LightMoney.MilliSatoshis(10001));
                Assert.True(retrievedInvoice.ExpiresAt > DateTimeOffset.UtcNow);
                retrievedInvoice = await client.Client.GetInvoice("c4180c13ae6b43e261c4c6f43c1b6760cfc80ba5a06643f383ece30d7316e4a6");

                Assert.Null(retrievedInvoice);
                retrievedInvoice = await client.Client.GetInvoice("lol");

                Assert.Null(retrievedInvoice);
            }
        }
Example #23
0
 public async Task <LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry, CancellationToken cancellation = default)
 {
     return(await(this as ILightningClient).CreateInvoice(new CreateInvoiceParams(amount, description, expiry), cancellation));
 }
Example #24
0
        public async Task <IActionResult> ProcessLightningPayout(string cryptoCode, string[] payoutIds)
        {
            await SetStoreContext();

            var pmi           = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike);
            var payoutHandler = _payoutHandlers.FindPayoutHandler(pmi);

            await using var ctx = _applicationDbContextFactory.CreateContext();

            var payouts = (await GetPayouts(ctx, pmi, payoutIds)).GroupBy(data => data.PullPaymentData.StoreId);
            var results = new List <ResultVM>();
            var network = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(pmi.CryptoCode);

            //we group per store and init the transfers by each
            async Task TrypayBolt(ILightningClient lightningClient, PayoutBlob payoutBlob, PayoutData payoutData, BOLT11PaymentRequest bolt11PaymentRequest)
            {
                var boltAmount = bolt11PaymentRequest.MinimumAmount.ToDecimal(LightMoneyUnit.BTC);

                if (boltAmount != payoutBlob.CryptoAmount)
                {
                    results.Add(new ResultVM()
                    {
                        PayoutId    = payoutData.Id,
                        Result      = PayResult.Error,
                        Message     = $"The BOLT11 invoice amount did not match the payout's amount ({boltAmount} instead of {payoutBlob.CryptoAmount})",
                        Destination = payoutBlob.Destination
                    });
                    return;
                }
                var result = await lightningClient.Pay(bolt11PaymentRequest.ToString());

                if (result.Result == PayResult.Ok)
                {
                    results.Add(new ResultVM()
                    {
                        PayoutId    = payoutData.Id,
                        Result      = result.Result,
                        Destination = payoutBlob.Destination
                    });
                    payoutData.State = PayoutState.Completed;
                }
                else
                {
                    results.Add(new ResultVM()
                    {
                        PayoutId    = payoutData.Id,
                        Result      = result.Result,
                        Destination = payoutBlob.Destination
                    });
                }
            }

            var authorizedForInternalNode = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded;

            foreach (var payoutDatas in payouts)
            {
                var store = payoutDatas.First().PullPaymentData.StoreData;

                var lightningSupportedPaymentMethod = store.GetSupportedPaymentMethods(_btcPayNetworkProvider)
                                                      .OfType <LightningSupportedPaymentMethod>()
                                                      .FirstOrDefault(method => method.PaymentId == pmi);

                if (lightningSupportedPaymentMethod.IsInternalNode && !authorizedForInternalNode)
                {
                    foreach (PayoutData payoutData in payoutDatas)
                    {
                        var blob = payoutData.GetBlob(_btcPayNetworkJsonSerializerSettings);
                        results.Add(new ResultVM
                        {
                            PayoutId    = payoutData.Id,
                            Result      = PayResult.Error,
                            Destination = blob.Destination,
                            Message     =
                                $"You are currently using the internal lightning node for this payout's store but you are not a server admin."
                        });
                    }

                    continue;
                }

                var client =
                    lightningSupportedPaymentMethod.CreateLightningClient(network, _options.Value,
                                                                          _lightningClientFactoryService);
                foreach (var payoutData in payoutDatas)
                {
                    var blob  = payoutData.GetBlob(_btcPayNetworkJsonSerializerSettings);
                    var claim = await payoutHandler.ParseClaimDestination(pmi, blob.Destination);

                    try
                    {
                        switch (claim.destination)
                        {
                        case LNURLPayClaimDestinaton lnurlPayClaimDestinaton:
                            var endpoint = LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out var tag);
                            var lightningPayoutHandler = (LightningLikePayoutHandler)payoutHandler;
                            var httpClient             = lightningPayoutHandler.CreateClient(endpoint);
                            var lnurlInfo =
                                (LNURLPayRequest)await LNURL.LNURL.FetchInformation(endpoint, "payRequest",
                                                                                    httpClient);

                            var lm = new LightMoney(blob.CryptoAmount.Value, LightMoneyUnit.BTC);
                            if (lm > lnurlInfo.MaxSendable || lm < lnurlInfo.MinSendable)
                            {
                                results.Add(new ResultVM()
                                {
                                    PayoutId    = payoutData.Id,
                                    Result      = PayResult.Error,
                                    Destination = blob.Destination,
                                    Message     =
                                        $"The LNURL provided would not generate an invoice of {lm.MilliSatoshi}msats"
                                });
                            }
                            else
                            {
                                try
                                {
                                    var lnurlPayRequestCallbackResponse =
                                        await lnurlInfo.SendRequest(lm, network.NBitcoinNetwork, httpClient);

                                    await TrypayBolt(client, blob, payoutData, lnurlPayRequestCallbackResponse.GetPaymentRequest(network.NBitcoinNetwork));
                                }
                                catch (LNUrlException e)
                                {
                                    results.Add(new ResultVM
                                    {
                                        PayoutId    = payoutData.Id,
                                        Result      = PayResult.Error,
                                        Destination = blob.Destination,
                                        Message     = e.Message
                                    });
                                }
                            }

                            break;

                        case BoltInvoiceClaimDestination item1:
                            await TrypayBolt(client, blob, payoutData, item1.PaymentRequest);

                            break;

                        default:
                            results.Add(new ResultVM
                            {
                                PayoutId    = payoutData.Id,
                                Result      = PayResult.Error,
                                Destination = blob.Destination,
                                Message     = claim.error
                            });
                            break;
                        }
                    }
                    catch (Exception)
                    {
                        results.Add(new ResultVM
                        {
                            PayoutId    = payoutData.Id,
                            Result      = PayResult.Error,
                            Destination = blob.Destination
                        });
                    }
                }
            }

            await ctx.SaveChangesAsync();

            return(View("LightningPayoutResult", results));
        }
 public string Open(NodeInfo node, Money fundingSatoshi, LightMoney pushAmount = null)
 {
     return(OpenAsync(node, fundingSatoshi, pushAmount).GetAwaiter().GetResult());
 }
 public string Receive(LightMoney amount, string description = null)
 {
     return(ReceiveAsync(amount, description).GetAwaiter().GetResult());
 }
        public async Task <IActionResult> ProcessLightningPayout(string cryptoCode, string[] payoutIds)
        {
            var pmi           = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike);
            var payoutHandler = _payoutHandlers.FindPayoutHandler(pmi);

            await using var ctx = _applicationDbContextFactory.CreateContext();

            var payouts = (await GetPayouts(ctx, pmi, payoutIds)).GroupBy(data => data.PullPaymentData.StoreId);
            var results = new List <ResultVM>();
            var network = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(pmi.CryptoCode);

            //we group per store and init the transfers by each
            async Task TrypayBolt(ILightningClient lightningClient, PayoutBlob payoutBlob, PayoutData payoutData,
                                  string destination)
            {
                var result = await lightningClient.Pay(destination);

                if (result.Result == PayResult.Ok)
                {
                    results.Add(new ResultVM()
                    {
                        PayoutId = payoutData.Id, Result = result.Result, Destination = payoutBlob.Destination
                    });
                    payoutData.State = PayoutState.Completed;
                }
                else
                {
                    results.Add(new ResultVM()
                    {
                        PayoutId = payoutData.Id, Result = result.Result, Destination = payoutBlob.Destination
                    });
                }
            }

            foreach (var payoutDatas in payouts)
            {
                var store = payoutDatas.First().PullPaymentData.StoreData;
                var lightningSupportedPaymentMethod = store.GetSupportedPaymentMethods(_btcPayNetworkProvider)
                                                      .OfType <LightningSupportedPaymentMethod>()
                                                      .FirstOrDefault(method => method.PaymentId == pmi);
                var client =
                    lightningSupportedPaymentMethod.CreateLightningClient(network, _options.Value,
                                                                          _lightningClientFactoryService);
                foreach (var payoutData in payoutDatas)
                {
                    var blob  = payoutData.GetBlob(_btcPayNetworkJsonSerializerSettings);
                    var claim = await payoutHandler.ParseClaimDestination(pmi, blob.Destination, false);

                    try
                    {
                        switch (claim.destination)
                        {
                        case LNURLPayClaimDestinaton lnurlPayClaimDestinaton:
                            var endpoint = LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out var tag);
                            var lightningPayoutHandler = (LightningLikePayoutHandler)payoutHandler;
                            var httpClient             = lightningPayoutHandler.CreateClient(endpoint);
                            var lnurlInfo =
                                (LNURLPayRequest)await LNURL.LNURL.FetchInformation(endpoint, "payRequest",
                                                                                    httpClient);

                            var lm = new LightMoney(blob.CryptoAmount.Value, LightMoneyUnit.BTC);
                            if (lm > lnurlInfo.MaxSendable || lm < lnurlInfo.MinSendable)
                            {
                                results.Add(new ResultVM()
                                {
                                    PayoutId    = payoutData.Id,
                                    Result      = PayResult.Error,
                                    Destination = blob.Destination,
                                    Message     =
                                        $"The LNURL provided would not generate an invoice of {lm.MilliSatoshi}msats"
                                });
                            }
                            else
                            {
                                try
                                {
                                    var lnurlPayRequestCallbackResponse =
                                        await lnurlInfo.SendRequest(lm, network.NBitcoinNetwork, httpClient);


                                    await TrypayBolt(client, blob, payoutData, lnurlPayRequestCallbackResponse.Pr);
                                }
                                catch (LNUrlException e)
                                {
                                    results.Add(new ResultVM()
                                    {
                                        PayoutId    = payoutData.Id,
                                        Result      = PayResult.Error,
                                        Destination = blob.Destination,
                                        Message     = e.Message
                                    });
                                }
                            }

                            break;

                        case BoltInvoiceClaimDestination item1:
                            await TrypayBolt(client, blob, payoutData, payoutData.Destination);

                            break;

                        default:
                            results.Add(new ResultVM()
                            {
                                PayoutId    = payoutData.Id,
                                Result      = PayResult.Error,
                                Destination = blob.Destination,
                                Message     = claim.error
                            });
                            break;
                        }
                    }
                    catch (Exception)
                    {
                        results.Add(new ResultVM()
                        {
                            PayoutId = payoutData.Id, Result = PayResult.Error, Destination = blob.Destination
                        });
                    }
                }
            }

            await ctx.SaveChangesAsync();

            return(View("LightningPayoutResult", results));
        }
 public CreateLightningInvoiceRequest(LightMoney amount, string description, TimeSpan expiry)
 {
     Amount      = amount;
     Description = description;
     Expiry      = expiry;
 }
Example #29
0
        public void CanUseLightMoney()
        {
            var light = LightMoney.MilliSatoshis(1);

            Assert.Equal("0.00000000001", light.ToString());
        }
Example #30
0
    protected override async Task Process(ISupportedPaymentMethod paymentMethod, PayoutData[] payouts)
    {
        await using var ctx = _applicationDbContextFactory.CreateContext();


        var lightningSupportedPaymentMethod = (LightningSupportedPaymentMethod)paymentMethod;

        if (lightningSupportedPaymentMethod.IsInternalNode &&
            !(await Task.WhenAll((await _storeRepository.GetStoreUsers(_PayoutProcesserSettings.StoreId))
                                 .Where(user => user.Role == StoreRoles.Owner).Select(user => user.Id)
                                 .Select(s => _userService.IsAdminUser(s)))).Any(b => b))
        {
            return;
        }

        var client =
            lightningSupportedPaymentMethod.CreateLightningClient(_network, _options.Value,
                                                                  _lightningClientFactoryService);



        foreach (var payoutData in payouts)
        {
            var blob  = payoutData.GetBlob(_btcPayNetworkJsonSerializerSettings);
            var claim = await _payoutHandler.ParseClaimDestination(PaymentMethodId, blob.Destination);

            try
            {
                switch (claim.destination)
                {
                case LNURLPayClaimDestinaton lnurlPayClaimDestinaton:
                    var endpoint   = LNURL.LNURL.Parse(lnurlPayClaimDestinaton.LNURL, out var tag);
                    var httpClient = _payoutHandler.CreateClient(endpoint);
                    var lnurlInfo  =
                        (LNURLPayRequest)await LNURL.LNURL.FetchInformation(endpoint, "payRequest",
                                                                            httpClient);

                    var lm = new LightMoney(blob.CryptoAmount.Value, LightMoneyUnit.BTC);
                    if (lm > lnurlInfo.MaxSendable || lm < lnurlInfo.MinSendable)
                    {
                        continue;
                    }
                    else
                    {
                        try
                        {
                            var lnurlPayRequestCallbackResponse =
                                await lnurlInfo.SendRequest(lm, _network.NBitcoinNetwork, httpClient);

                            if (await TrypayBolt(client, blob, payoutData,
                                                 lnurlPayRequestCallbackResponse
                                                 .GetPaymentRequest(_network.NBitcoinNetwork)))
                            {
                                ctx.Attach(payoutData);
                                payoutData.State = PayoutState.Completed;
                            }
                        }
                        catch (LNUrlException)
                        {
                            continue;
                        }
                    }

                    break;

                case BoltInvoiceClaimDestination item1:
                    if (await TrypayBolt(client, blob, payoutData, item1.PaymentRequest))
                    {
                        ctx.Attach(payoutData);
                        payoutData.State = PayoutState.Completed;
                    }

                    break;
                }
            }
            catch (Exception e)
            {
                Logs.PayServer.LogError(e, $"Could not process payout {payoutData.Id}");
            }
        }


        await ctx.SaveChangesAsync();
    }