mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
fixes
This commit is contained in:
@@ -81,8 +81,8 @@ Global
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -97,48 +97,48 @@ Global
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -149,12 +149,12 @@ Global
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Altcoins-Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=b4e2ed08_002D4ad3_002D4648_002D8bdb_002D3107200460b9_0023BTCPayServer_002EPlugins_002ELiquidPlus/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nostr/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -1,23 +1,17 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Lightning.LndHub;
|
||||
using GraphQL;
|
||||
using GraphQL.Client.Http;
|
||||
using GraphQL.Client.Serializer.Newtonsoft;
|
||||
using Microsoft.AspNetCore.OutputCaching;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Network = NBitcoin.Network;
|
||||
|
||||
@@ -32,18 +26,20 @@ public class BlinkLightningClient : ILightningClient
|
||||
public string? WalletCurrency { get; set; }
|
||||
|
||||
private readonly Network _network;
|
||||
private readonly NBXplorerDashboard _nbXplorerDashboard;
|
||||
private readonly GraphQLHttpClient _client;
|
||||
|
||||
public BlinkLightningClient(string apiKey, Uri apiEndpoint, string walletId, Network network,
|
||||
NBXplorerDashboard nbXplorerDashboard, HttpClient httpClient)
|
||||
public BlinkLightningClient(string apiKey, Uri apiEndpoint, string walletId, Network network, HttpClient httpClient)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_apiEndpoint = apiEndpoint;
|
||||
WalletId = walletId;
|
||||
_network = network;
|
||||
_nbXplorerDashboard = nbXplorerDashboard;
|
||||
_client = new GraphQLHttpClient(new GraphQLHttpClientOptions() {EndPoint = _apiEndpoint}, new NewtonsoftJsonSerializer(), httpClient);
|
||||
_client = new GraphQLHttpClient(new GraphQLHttpClientOptions() {EndPoint = _apiEndpoint, WebSocketEndPoint = new Uri( "wss://" + _apiEndpoint.Host.Replace("api.", "ws.") + _apiEndpoint.PathAndQuery), ConfigureWebsocketOptions =
|
||||
options =>
|
||||
{
|
||||
options.SetRequestHeader("X-API-KEY", apiKey);
|
||||
}}, new NewtonsoftJsonSerializer(), httpClient);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -301,23 +297,9 @@ query Transactions($walletId: WalletId!) {
|
||||
public async Task<LightningInvoice> CreateInvoice(CreateInvoiceParams createInvoiceRequest,
|
||||
CancellationToken cancellation = new())
|
||||
{
|
||||
var query = @"
|
||||
mutation lnInvoiceCreate($input: LnInvoiceCreateOnBehalfOfRecipientInput!) {
|
||||
lnInvoiceCreateOnBehalfOfRecipient(input: $input) {
|
||||
invoice {
|
||||
createdAt
|
||||
paymentHash
|
||||
paymentRequest
|
||||
paymentSecret
|
||||
paymentStatus
|
||||
satoshis
|
||||
}
|
||||
}
|
||||
}";
|
||||
string query;
|
||||
|
||||
if (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true)
|
||||
{
|
||||
query = @"
|
||||
query = WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true ? @"
|
||||
mutation lnInvoiceCreate($input: LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput!) {
|
||||
lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient(input: $input) {
|
||||
invoice {
|
||||
@@ -327,10 +309,27 @@ mutation lnInvoiceCreate($input: LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecip
|
||||
paymentSecret
|
||||
paymentStatus
|
||||
satoshis
|
||||
},
|
||||
errors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}" : @"
|
||||
mutation lnInvoiceCreate($input: LnInvoiceCreateOnBehalfOfRecipientInput!) {
|
||||
lnInvoiceCreateOnBehalfOfRecipient(input: $input) {
|
||||
invoice {
|
||||
createdAt
|
||||
paymentHash
|
||||
paymentRequest
|
||||
paymentSecret
|
||||
paymentStatus
|
||||
satoshis
|
||||
},
|
||||
errors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}";
|
||||
}
|
||||
|
||||
var reques = new GraphQLRequest
|
||||
{
|
||||
@@ -350,142 +349,101 @@ expiresIn = (int)createInvoiceRequest.Expiry.TotalMinutes
|
||||
}
|
||||
};
|
||||
var response = await _client.SendQueryAsync<dynamic>(reques, cancellation);
|
||||
var inv = (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true
|
||||
? response.Data.lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient.invoice
|
||||
: response.Data.lnInvoiceCreateOnBehalfOfRecipient.invoice)as JObject;
|
||||
|
||||
if (inv is null)
|
||||
{
|
||||
var errors = (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true
|
||||
? response.Data.lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient.errors
|
||||
: response.Data.lnInvoiceCreateOnBehalfOfRecipient.errors) as JArray;
|
||||
|
||||
return ToInvoice(response.Data.lnInvoiceCreate.invoice);
|
||||
if (errors.Any())
|
||||
{
|
||||
throw new Exception(errors.First()["message"].ToString());
|
||||
}
|
||||
}
|
||||
return ToInvoice(inv);
|
||||
}
|
||||
|
||||
public async Task<ILightningInvoiceListener> Listen(CancellationToken cancellation = new CancellationToken())
|
||||
{
|
||||
return new BlinkListener(this, cancellation);
|
||||
return new BlinkListener(_client, this);
|
||||
}
|
||||
|
||||
|
||||
public class BlinkListener : ILightningInvoiceListener
|
||||
{
|
||||
private readonly ILightningClient _client;
|
||||
private readonly BlinkLightningClient _lightningClient;
|
||||
private readonly Channel<LightningInvoice> _invoices = Channel.CreateUnbounded<LightningInvoice>();
|
||||
private readonly CancellationTokenSource _cts;
|
||||
private HttpClient _httpClient;
|
||||
private HttpResponseMessage _response;
|
||||
private Stream _body;
|
||||
private StreamReader _reader;
|
||||
private Task _listenLoop;
|
||||
private readonly List<string> _paidInvoiceIds;
|
||||
private readonly IDisposable _subscription;
|
||||
|
||||
public BlinkListener(ILightningClient client, CancellationToken cancellation)
|
||||
public BlinkListener(GraphQLHttpClient httpClient, BlinkLightningClient lightningClient)
|
||||
{
|
||||
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellation);
|
||||
_client = client;
|
||||
_paidInvoiceIds = new List<string>();
|
||||
_listenLoop = ListenLoop();
|
||||
try
|
||||
{
|
||||
|
||||
_lightningClient = lightningClient;
|
||||
var stream = httpClient.CreateSubscriptionStream<dynamic>(new GraphQLRequest()
|
||||
{
|
||||
Query = @"subscription myUpdates {
|
||||
myUpdates {
|
||||
update {
|
||||
... on LnUpdate {
|
||||
transaction {
|
||||
initiationVia {
|
||||
... on InitiationViaLn {
|
||||
paymentHash
|
||||
}
|
||||
}
|
||||
direction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
", OperationName = "myUpdates"
|
||||
});
|
||||
|
||||
_subscription = stream.Subscribe(async response =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var x = stream;
|
||||
var y = _lightningClient;
|
||||
if (response.Data.myUpdates.update.transaction.direction != "RECEIVE")
|
||||
return;
|
||||
if ((await _lightningClient.GetInvoice(response.Data.myUpdates.update.transaction.initiationVia
|
||||
.paymentHash.ToString())) is LightningInvoice inv)
|
||||
{
|
||||
|
||||
_invoices.Writer.TryWrite(inv);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_subscription.Dispose();
|
||||
_invoices.Writer.TryComplete();
|
||||
}
|
||||
|
||||
public async Task<LightningInvoice> WaitInvoice(CancellationToken cancellation)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _invoices.Reader.ReadAsync(cancellation);
|
||||
}
|
||||
catch (ChannelClosedException ex) when (ex.InnerException == null)
|
||||
{
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
catch (ChannelClosedException ex)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
static readonly AsyncDuplicateLock _locker = new();
|
||||
static readonly ConcurrentDictionary<string, LightningInvoice[]> _activeListeners = new();
|
||||
|
||||
private async Task ListenLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
var releaser = await _locker.LockOrBustAsync(_client.ToString(), _cts.Token);
|
||||
if (releaser is null)
|
||||
{
|
||||
while (!_cts.IsCancellationRequested && releaser is null)
|
||||
{
|
||||
if (_activeListeners.TryGetValue(_client.ToString(), out var invoicesData))
|
||||
{
|
||||
await HandleInvoicesData(invoicesData);
|
||||
}
|
||||
|
||||
releaser = await _locker.LockOrBustAsync(_client.ToString(), _cts.Token);
|
||||
|
||||
if (releaser is null)
|
||||
await Task.Delay(2500, _cts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
using (releaser)
|
||||
{
|
||||
while (!_cts.IsCancellationRequested)
|
||||
{
|
||||
var invoicesData = await _client.ListInvoices(_cts.Token);
|
||||
_activeListeners.AddOrReplace(_client.ToString(), invoicesData);
|
||||
await HandleInvoicesData(invoicesData);
|
||||
|
||||
await Task.Delay(2500, _cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch when (_cts.IsCancellationRequested)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_invoices.Writer.TryComplete(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_activeListeners.TryRemove(_client.ToString(), out _);
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleInvoicesData(IEnumerable<LightningInvoice> invoicesData)
|
||||
{
|
||||
foreach (var data in invoicesData)
|
||||
{
|
||||
var invoice = data;
|
||||
if (invoice.PaidAt != null && !_paidInvoiceIds.Contains(invoice.Id))
|
||||
{
|
||||
await _invoices.Writer.WriteAsync(invoice, _cts.Token);
|
||||
_paidInvoiceIds.Add(invoice.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose(bool waitLoop)
|
||||
{
|
||||
if (_cts.IsCancellationRequested)
|
||||
return;
|
||||
_cts.Cancel();
|
||||
_reader?.Dispose();
|
||||
_reader = null;
|
||||
_body?.Dispose();
|
||||
_body = null;
|
||||
_response?.Dispose();
|
||||
_response = null;
|
||||
_httpClient?.Dispose();
|
||||
_httpClient = null;
|
||||
if (waitLoop)
|
||||
_listenLoop?.Wait();
|
||||
_invoices.Writer.TryComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(Network Network, string DefaultWalletId)> GetNetworkAndDefaultWallet(CancellationToken cancellation =default)
|
||||
public async Task<(Network Network, string DefaultWalletId, string DefaultWalletCurrency)> GetNetworkAndDefaultWallet(CancellationToken cancellation =default)
|
||||
{
|
||||
|
||||
var reques = new GraphQLRequest
|
||||
@@ -497,7 +455,10 @@ query GetNetworkAndDefaultWallet {
|
||||
}
|
||||
me {
|
||||
defaultAccount {
|
||||
defaultWalletId
|
||||
defaultWallet{
|
||||
id
|
||||
currency
|
||||
}
|
||||
}
|
||||
}
|
||||
}",
|
||||
@@ -506,7 +467,8 @@ query GetNetworkAndDefaultWallet {
|
||||
|
||||
var response = await _client.SendQueryAsync<dynamic>(reques, cancellation);
|
||||
|
||||
var defaultWalletId = (string) response.Data.me.defaultAccount.defaultWalletId;
|
||||
var defaultWalletId = (string) response.Data.me.defaultAccount.defaultWallet.id;
|
||||
var defaultWalletCurrency = (string) response.Data.me.defaultAccount.defaultWallet.currency;
|
||||
var network = response.Data.globals.network.ToString() switch
|
||||
{
|
||||
"mainnet" => Network.Main,
|
||||
@@ -514,31 +476,13 @@ query GetNetworkAndDefaultWallet {
|
||||
"regtest" => Network.RegTest,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
return (network, defaultWalletId);
|
||||
return (network, defaultWalletId, defaultWalletCurrency);
|
||||
}
|
||||
|
||||
public async Task<LightningNodeInformation> GetInfo(CancellationToken cancellation = new CancellationToken())
|
||||
public Task<LightningNodeInformation> GetInfo(CancellationToken cancellation = new CancellationToken())
|
||||
{
|
||||
|
||||
var reques = new GraphQLRequest
|
||||
{
|
||||
Query = @"
|
||||
query Globals {
|
||||
globals {
|
||||
nodesIds
|
||||
}
|
||||
}",
|
||||
OperationName = "Globals"
|
||||
};
|
||||
var response = await _client.SendQueryAsync<dynamic>(reques, cancellation);
|
||||
var result = new LightningNodeInformation()
|
||||
{
|
||||
BlockHeight = _nbXplorerDashboard.Get("BTC").Status.ChainHeight,
|
||||
Alias = "Blink",
|
||||
|
||||
};
|
||||
result.NodeInfoList.AddRange(((JArray)response.Data.globals.nodesIds).Select(s => new NodeInfo(new PubKey(s.Value<string>()), "galoy.com", 69)));
|
||||
return result;
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public async Task<LightningNodeBalance> GetBalance(CancellationToken cancellation = new())
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using Network = NBitcoin.Network;
|
||||
|
||||
@@ -11,13 +10,10 @@ namespace BTCPayServer.Plugins.Blink;
|
||||
public class BlinkLightningConnectionStringHandler : ILightningConnectionStringHandler
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly NBXplorerDashboard _nbXplorerDashboard;
|
||||
|
||||
public BlinkLightningConnectionStringHandler(IHttpClientFactory httpClientFactory,
|
||||
NBXplorerDashboard nbXplorerDashboard)
|
||||
public BlinkLightningConnectionStringHandler(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_nbXplorerDashboard = nbXplorerDashboard;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +28,9 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH
|
||||
|
||||
if (!kv.TryGetValue("server", out var server))
|
||||
{
|
||||
error = $"The key 'server' is mandatory for blink connection strings";
|
||||
return null;
|
||||
server = "https://api.blink.sv/graphql";
|
||||
// error = $"The key 'server' is mandatory for blink connection strings";
|
||||
// return null;
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(server, UriKind.Absolute, out var uri)
|
||||
@@ -77,8 +74,8 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH
|
||||
client.BaseAddress = uri;
|
||||
|
||||
kv.TryGetValue("wallet-id", out var walletId);
|
||||
var bclient = new BlinkLightningClient(apiKey, uri, walletId, network, _nbXplorerDashboard, client);
|
||||
(Network Network, string DefaultWalletId) res;
|
||||
var bclient = new BlinkLightningClient(apiKey, uri, walletId, network, client);
|
||||
(Network Network, string DefaultWalletId, string DefaultWalletCurrency) res;
|
||||
try
|
||||
{
|
||||
res = bclient.GetNetworkAndDefaultWallet().GetAwaiter().GetResult();
|
||||
@@ -103,6 +100,7 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH
|
||||
if (walletId is null)
|
||||
{
|
||||
bclient.WalletId = res.DefaultWalletId;
|
||||
bclient.WalletCurrency = res.DefaultWalletCurrency;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<code><b>type=</b>blink;<b>server=</b>https://api.blink.sv/graphql;<b>api-key</b>=blink_...;<b>wallet-id=</b>xyz</code>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="my-2">Head over to the Blink dashboard and create an api key. The wallet-id is optional and will use the default wallet otherwise.</p>
|
||||
<p class="my-2">Head over to the <a href="https://dashboard.blink.sv" target="_blank" rel="noreferrer noopener" >Blink dashboard</a> and create an api key. The server is optional and will use the default Blink instance.The wallet-id is optional and will use the default wallet otherwise.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<LangVersion>10</LangVersion>
|
||||
<Configurations>Debug;Release;Altcoins-Debug;Altcoins-Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<DefineConstants>$(DefineConstants);ALTCOINS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Plugin specific properties -->
|
||||
@@ -31,18 +32,6 @@
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<Altcoins>true</Altcoins>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<Altcoins>true</Altcoins>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Altcoins)' == 'true'">
|
||||
<DefineConstants>$(DefineConstants);ALTCOINS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\**" />
|
||||
<ProjectReference Include="..\..\submodules\btcpayserver\BTCPayServer\BTCPayServer.csproj">
|
||||
|
||||
@@ -10,6 +10,7 @@ using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Common;
|
||||
using BTCPayServer.Plugins.Altcoins;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Plugins.Altcoins;
|
||||
using BTCPayServer.Plugins.LiquidPlus.Services;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer.Plugins.LiquidPlus
|
||||
{
|
||||
@@ -18,33 +24,51 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
};
|
||||
public override void Execute(IServiceCollection services)
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
var services = (PluginServiceCollection) applicationBuilder;
|
||||
if (services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>()
|
||||
.GetFromCryptoCode("LBTC") is null || !services.BootstrapServices.GetRequiredService<SelectedChains>().Contains("LBTC"))
|
||||
return;
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("LiquidNav", "store-integrations-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("OnChainWalletSetupLiquidExtension", "onchain-wallet-setup-post-body"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("OnChainWalletSetupLiquidExtension",
|
||||
"onchain-wallet-setup-post-body"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("CustomLiquidAssetsNavExtension", "server-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("StoreNavLiquidExtension", "store-nav"));
|
||||
services.AddSingleton<CustomLiquidAssetsRepository>();
|
||||
|
||||
var originalImplementationFactory = services.Single(descriptor =>
|
||||
descriptor.Lifetime == ServiceLifetime.Singleton &&
|
||||
descriptor.ServiceType == typeof(BTCPayNetworkProvider));
|
||||
services.Replace(ServiceDescriptor.Singleton(provider =>
|
||||
|
||||
var config = services.BootstrapServices.GetRequiredService<IConfiguration>();
|
||||
DataDirectories dataDirectories = new DataDirectories();
|
||||
dataDirectories.Configure(config);
|
||||
|
||||
var repo = new CustomLiquidAssetsRepository(new NullLogger<CustomLiquidAssetsRepository>(),
|
||||
new OptionsWrapper<DataDirectories>(dataDirectories));
|
||||
var settings = repo.Get();
|
||||
var template = (ElementsBTCPayNetwork) services.Single(descriptor =>
|
||||
descriptor.ServiceType == typeof(BTCPayNetworkBase) &&
|
||||
descriptor.ImplementationInstance is ElementsBTCPayNetwork
|
||||
{
|
||||
var _customLiquidAssetsRepository = provider.GetService<CustomLiquidAssetsRepository>();
|
||||
var _logger = provider.GetService<ILogger<LiquidPlusPlugin>>();
|
||||
var networkProvider =
|
||||
(originalImplementationFactory.ImplementationInstance ??
|
||||
originalImplementationFactory.ImplementationFactory.Invoke(provider)) as BTCPayNetworkProvider;
|
||||
if (networkProvider.Support("LBTC"))
|
||||
CryptoCode: "LBTC"
|
||||
})
|
||||
.ImplementationInstance;
|
||||
var tlProvider = (TransactionLinkProviders.Entry) services.Single(descriptor =>
|
||||
descriptor.ServiceType == typeof(TransactionLinkProviders.Entry) &&
|
||||
descriptor.ImplementationInstance is TransactionLinkProviders.Entry
|
||||
{
|
||||
var settings = _customLiquidAssetsRepository.Get();
|
||||
var template = networkProvider.GetNetwork<ElementsBTCPayNetwork>("LBTC");
|
||||
var additionalNetworks = settings.Items.Select(configuration => new ElementsBTCPayNetwork()
|
||||
PaymentMethodId: {CryptoCode: "LBTC"}
|
||||
})
|
||||
.ImplementationInstance;
|
||||
settings.Items.ForEach(configuration =>
|
||||
|
||||
{
|
||||
CryptoCode = configuration.CryptoCode
|
||||
var code = configuration.CryptoCode
|
||||
.Replace("-", "")
|
||||
.Replace("_", ""),
|
||||
.Replace("_", "");
|
||||
services.AddBTCPayNetwork(new ElementsBTCPayNetwork()
|
||||
{
|
||||
CryptoCode = code,
|
||||
DefaultRateRules = configuration.DefaultRateRules ?? Array.Empty<string>(),
|
||||
AssetId = uint256.Parse(configuration.AssetId),
|
||||
Divisibility = configuration.Divisibility,
|
||||
@@ -64,30 +88,9 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
CoinType = template.CoinType,
|
||||
VaultSupported = template.VaultSupported,
|
||||
MaxTrackedConfirmation = template.MaxTrackedConfirmation,
|
||||
BlockExplorerLinkDefault = template.BlockExplorerLinkDefault,
|
||||
SupportRBF = template.SupportRBF
|
||||
}).AddTransactionLinkProvider(new PaymentMethodId(code, PaymentTypes.BTCLike), tlProvider.Provider);
|
||||
});
|
||||
var newCryptoCodes = settings.Items.Select(configuration => configuration.CryptoCode).ToArray();
|
||||
_logger.LogInformation($"Loaded {newCryptoCodes.Length} " +
|
||||
$"{(!newCryptoCodes.Any()?string.Empty: $"({string.Join(',', newCryptoCodes)})")} additional liquid assets");
|
||||
var newSupportedChains = networkProvider.GetAll().Select(b => b.CryptoCode).Concat(newCryptoCodes).ToArray();
|
||||
return new BTCPayNetworkProviderOverride(networkProvider.NetworkType, additionalNetworks).Filter(newSupportedChains);
|
||||
}
|
||||
|
||||
return networkProvider;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public class BTCPayNetworkProviderOverride : BTCPayNetworkProvider
|
||||
{
|
||||
public BTCPayNetworkProviderOverride(ChainName networkType,
|
||||
IEnumerable<ElementsBTCPayNetwork> elementsBTCPayNetworks) : base(networkType)
|
||||
{
|
||||
foreach (ElementsBTCPayNetwork elementsBTCPayNetwork in elementsBTCPayNetworks)
|
||||
{
|
||||
_Networks.TryAdd(elementsBTCPayNetwork.CryptoCode.ToUpperInvariant(), elementsBTCPayNetwork);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Plugins.Altcoins
|
||||
@using BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using Microsoft.AspNetCore.Routing
|
||||
|
||||
@inject BTCPayNetworkProvider BTCPayNetworkProvider;
|
||||
@@ -13,7 +16,7 @@
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(storeId) && (BTCPayNetworkProvider.GetAll().OfType<ElementsBTCPayNetwork>().Any()))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-route-storeId="@storeId" asp-action="GenerateLiquidScript" asp-controller="StoreLiquid" class="nav-link js-scroll-trigger @(isActive ? "active" : string.Empty)">
|
||||
<svg role="img" class="icon">
|
||||
</svg>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Models.StoreViewModels
|
||||
@using BTCPayServer.Plugins.Altcoins
|
||||
@using NBitcoin
|
||||
@using NBitcoin.Altcoins.Elements
|
||||
@model dynamic
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Plugins.Altcoins
|
||||
@using BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using Microsoft.AspNetCore.Routing
|
||||
@inject BTCPayNetworkProvider BTCPayNetworkProvider;
|
||||
@inject IScopeProvider ScopeProvider
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Prism</Product>
|
||||
<Description>Automated value splits for Bitcoin.</Description>
|
||||
<Version>1.2.1</Version>
|
||||
<Version>1.2.2</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Components.UIExtensionPoint
|
||||
@using BTCPayServer.Plugins.Prism.Components
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@@ -15,6 +14,4 @@
|
||||
{
|
||||
StoreId = ScopeProvider.GetCurrentStoreId(),
|
||||
}))
|
||||
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
<vc:ui-extension-point location="prism-edit" model="@Model"></vc:ui-extension-point>
|
||||
Submodule submodules/btcpayserver updated: 3f344f2c0c...cb54f8f6d1
Reference in New Issue
Block a user