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()); }
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); }
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)); }
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)); }
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)); }
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" }); }
//[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); }
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" }); }
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"); }
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)); } }
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);
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); }
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); } }
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)); }
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; }
public void CanUseLightMoney() { var light = LightMoney.MilliSatoshis(1); Assert.Equal("0.00000000001", light.ToString()); }
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(); }