This commit is contained in:
Kukks
2023-12-20 09:29:32 +01:00
parent d24f2b54f6
commit 028e58d438
14 changed files with 223 additions and 285 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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())

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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">

View File

@@ -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;

View File

@@ -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);
}
}
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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 -->

View File

@@ -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>