mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
wip
This commit is contained in:
@@ -2,12 +2,17 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Breez.Sdk;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
|
using BTCPayServer.Models;
|
||||||
|
using BTCPayServer.Services.Wallets;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NBXplorer.DerivationStrategy;
|
||||||
|
|
||||||
namespace BTCPayServer.Plugins.Breez;
|
namespace BTCPayServer.Plugins.Breez;
|
||||||
|
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||||
[Route("plugins/{storeId}/Breez")]
|
[Route("plugins/{storeId}/Breez")]
|
||||||
@@ -15,26 +20,201 @@ public class BreezController : Controller
|
|||||||
{
|
{
|
||||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||||
private readonly BreezService _breezService;
|
private readonly BreezService _breezService;
|
||||||
|
private readonly BTCPayWalletProvider _btcWalletProvider;
|
||||||
|
|
||||||
public BreezController(BTCPayNetworkProvider btcPayNetworkProvider, BreezService breezService)
|
public BreezController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||||
|
BreezService breezService,
|
||||||
|
BTCPayWalletProvider btcWalletProvider)
|
||||||
{
|
{
|
||||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||||
_breezService = breezService;
|
_breezService = breezService;
|
||||||
|
_btcWalletProvider = btcWalletProvider;
|
||||||
}
|
}
|
||||||
[HttpGet("")]
|
|
||||||
|
|
||||||
|
[HttpGet("")]
|
||||||
public async Task<IActionResult> Index(string storeId)
|
public async Task<IActionResult> Index(string storeId)
|
||||||
{
|
{
|
||||||
return View(await _breezService.Get(storeId));
|
var client = _breezService.GetClient(storeId);
|
||||||
|
return RedirectToAction(client is null ? nameof(Configure) : nameof(Info), new {storeId});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("swapin")]
|
||||||
|
public async Task<IActionResult> SwapIn(string storeId)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("info")]
|
||||||
|
public async Task<IActionResult> Info(string storeId)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("sweep")]
|
||||||
|
public async Task<IActionResult> Sweep(string storeId)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("sweep")]
|
||||||
|
public async Task<IActionResult> Sweep(string storeId, string address, uint satPerByte)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.Equals("store", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var store = ControllerContext.HttpContext.GetStoreData()
|
||||||
|
.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||||
|
var res = await _btcWalletProvider.GetWallet(storeId)
|
||||||
|
.ReserveAddressAsync(storeId, store.AccountDerivation, "Breez");
|
||||||
|
address = res.Address.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = client.Sdk.Sweep(new SweepRequest(address, satPerByte));
|
||||||
|
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = $"sweep successful: {response.txid}";
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = $"error with sweep: {e.Message}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("swapin/create")]
|
||||||
|
public async Task<IActionResult> SwapInCreate(string storeId)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Sdk.ReceiveOnchain(new ReceiveOnchainRequest());
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = "Swapin created successfully";
|
||||||
|
return RedirectToAction(nameof(SwapIn), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("swapout")]
|
||||||
|
public async Task<IActionResult> SwapOut(string storeId)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("swapout")]
|
||||||
|
public async Task<IActionResult> SwapOut(string storeId, string address, ulong amount, uint satPerByte,
|
||||||
|
string feesHash)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.Equals("store", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var store = ControllerContext.HttpContext.GetStoreData()
|
||||||
|
.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||||
|
var res = await _btcWalletProvider.GetWallet(storeId)
|
||||||
|
.ReserveAddressAsync(storeId, store.AccountDerivation, "Breez");
|
||||||
|
address = res.Address.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = client.Sdk.SendOnchain(new SendOnchainRequest(amount, address, feesHash, satPerByte));
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = $"swap out created: {result.reverseSwapInfo.id}";
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = $"Couldnt create swap out: {e.Message}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction("SwapOut", new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("swapin/{address}/refund")]
|
||||||
|
public async Task<IActionResult> SwapInRefund(string storeId, string address)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
return View((object) storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("swapin/{address}/refund")]
|
||||||
|
public async Task<IActionResult> SwapInRefund(string storeId, string address, string refundAddress, uint satPerByte)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var resp = client.Sdk.Refund(new RefundRequest(address, refundAddress, satPerByte));
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = $"Refund tx: {resp.refundTxId}";
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = $"Couldnt refund: {e.Message}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction(nameof(SwapIn), new {storeId});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("configure")]
|
||||||
|
public async Task<IActionResult> Configure(string storeId)
|
||||||
|
{
|
||||||
|
return View(await _breezService.Get(storeId));
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("")]
|
[HttpPost("")]
|
||||||
public async Task<IActionResult> Index(string storeId, string command, BreezSettings settings)
|
public async Task<IActionResult> Configure(string storeId, string command, BreezSettings settings)
|
||||||
{
|
{
|
||||||
if (command == "clear")
|
if (command == "clear")
|
||||||
{
|
{
|
||||||
await _breezService.Set(storeId, null);
|
await _breezService.Set(storeId, null);
|
||||||
TempData[WellKnownTempData.SuccessMessage] = "Settings cleared successfully";
|
TempData[WellKnownTempData.SuccessMessage] = "Settings cleared successfully";
|
||||||
return RedirectToAction(nameof(Index), new {storeId});
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "save")
|
if (command == "save")
|
||||||
@@ -50,9 +230,31 @@ public class BreezController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
TempData[WellKnownTempData.SuccessMessage] = "Settings saved successfully";
|
TempData[WellKnownTempData.SuccessMessage] = "Settings saved successfully";
|
||||||
return RedirectToAction(nameof(Index), new {storeId});
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
}
|
}
|
||||||
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("payments")]
|
||||||
|
public async Task<IActionResult> Payments(string storeId, PaymentsViewModel viewModel)
|
||||||
|
{
|
||||||
|
var client = _breezService.GetClient(storeId);
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Configure), new {storeId});
|
||||||
|
}
|
||||||
|
viewModel ??= new PaymentsViewModel();
|
||||||
|
|
||||||
|
viewModel.Payments = client.Sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.ALL, null, null, null,
|
||||||
|
(uint?) viewModel.Skip, (uint?) viewModel.Count));
|
||||||
|
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PaymentsViewModel : BasePagingViewModel
|
||||||
|
{
|
||||||
|
public List<Payment> Payments { get; set; } = new();
|
||||||
|
public override int CurrentPageCount => Payments.Count;
|
||||||
}
|
}
|
||||||
@@ -20,13 +20,13 @@ public class BreezLightningConnectionStringHandler : ILightningConnectionStringH
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kv.TryGetValue("store", out var storeId))
|
if (!kv.TryGetValue("key", out var key))
|
||||||
{
|
{
|
||||||
error = $"The key 'store' is mandatory for breez connection strings";
|
error = $"The key 'key' is mandatory for breez connection strings";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = null;
|
error = null;
|
||||||
return _breezService.GetClient(storeId);
|
return _breezService.GetClientByPaymentKey(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ namespace BTCPayServer.Plugins.Breez
|
|||||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/LNPaymentMethodSetupTabhead", "ln-payment-method-setup-tabhead"));
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/LNPaymentMethodSetupTabhead", "ln-payment-method-setup-tabhead"));
|
||||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/LNPaymentMethodSetupTab", "ln-payment-method-setup-tab"));
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/LNPaymentMethodSetupTab", "ln-payment-method-setup-tab"));
|
||||||
|
|
||||||
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/BreezNodeInfo",
|
||||||
|
"dashboard"));
|
||||||
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Breez/BreezPaymentsTable",
|
||||||
|
"dashboard"));
|
||||||
base.Execute(applicationBuilder);
|
base.Execute(applicationBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Configuration;
|
using BTCPayServer.Configuration;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Payments;
|
||||||
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -106,7 +109,17 @@ public class BreezService:IHostedService
|
|||||||
await _storeRepository.UpdateSetting(storeId, "Breez", settings!);
|
await _storeRepository.UpdateSetting(storeId, "Breez", settings!);
|
||||||
if (settings is null)
|
if (settings is null)
|
||||||
{
|
{
|
||||||
_settings.Remove(storeId);
|
_settings.Remove(storeId, out var oldSettings );
|
||||||
|
var data = await _storeRepository.FindStore(storeId);
|
||||||
|
var existing = data?.GetSupportedPaymentMethods(_btcPayNetworkProvider)
|
||||||
|
.OfType<LightningSupportedPaymentMethod>().FirstOrDefault(method =>
|
||||||
|
method.CryptoCode == "BTC" && method.PaymentId.PaymentType == LightningPaymentType.Instance);
|
||||||
|
var isBreez = existing?.GetExternalLightningUrl() == $"type=breez;key={oldSettings.PaymentKey}";
|
||||||
|
if (isBreez)
|
||||||
|
{
|
||||||
|
data.SetSupportedPaymentMethod(new PaymentMethodId("BTC", LightningPaymentType.Instance), null );
|
||||||
|
await _storeRepository.UpdateStore(data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(result is not null )
|
else if(result is not null )
|
||||||
@@ -122,9 +135,18 @@ public class BreezService:IHostedService
|
|||||||
_clients.Values.ToList().ForEach(c => c.Dispose());
|
_clients.Values.ToList().ForEach(c => c.Dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BreezLightningClient? GetClient(string storeId)
|
public BreezLightningClient? GetClient(string? storeId)
|
||||||
{
|
{
|
||||||
|
if(storeId is null)
|
||||||
|
return null;
|
||||||
_clients.TryGetValue(storeId, out var client);
|
_clients.TryGetValue(storeId, out var client);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
public BreezLightningClient? GetClientByPaymentKey(string? paymentKey)
|
||||||
|
{
|
||||||
|
if(paymentKey is null)
|
||||||
|
return null;
|
||||||
|
var match = _settings.FirstOrDefault(pair => pair.Value.PaymentKey == paymentKey).Key;
|
||||||
|
return GetClient(match);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace BTCPayServer.Plugins.Breez;
|
namespace BTCPayServer.Plugins.Breez;
|
||||||
|
|
||||||
public class BreezSettings
|
public class BreezSettings
|
||||||
@@ -6,4 +8,6 @@ public class BreezSettings
|
|||||||
public string InviteCode { get; set; }
|
public string InviteCode { get; set; }
|
||||||
public string Mnemonic { get; set; }
|
public string Mnemonic { get; set; }
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
|
|
||||||
|
public string PaymentKey { get; set; } = Guid.NewGuid().ToString();
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,25 @@
|
|||||||
@model BTCPayServer.Plugins.Breez.BreezSettings?
|
@model BTCPayServer.Plugins.Breez.BreezSettings?
|
||||||
@inject BreezService BreezService
|
@inject BreezService BreezService
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage("Breez", "Breez", "Breez");
|
ViewData.SetActivePage("Breez", "Configure", "Configure");
|
||||||
var storeId = Context.GetCurrentStoreId();
|
var storeId = Context.GetCurrentStoreId();
|
||||||
}
|
}
|
||||||
|
<form method="post" asp-action="Configure" asp-controller="Breez" asp-route-storeId="@storeId">
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
<button name="command" type="submit" value="save" class="btn btn-primary">Save</button>
|
||||||
|
@if (await BreezService.Get(storeId) is not null)
|
||||||
|
{
|
||||||
|
<button name="command" type="submit" value="clear" class="btn btn-danger">Clear</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<partial name="_StatusMessage"/>
|
|
||||||
|
|
||||||
<h2 class="mb-4">@ViewData["Title"]</h2>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-10">
|
|
||||||
<form method="post">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Mnemonic" class="form-label">Mnemonic</label>
|
<label asp-for="Mnemonic" class="form-label">Mnemonic</label>
|
||||||
<input asp-for="Mnemonic" class="form-control"/>
|
<input asp-for="Mnemonic" class="form-control"/>
|
||||||
@@ -34,20 +41,8 @@
|
|||||||
<span asp-validation-for="InviteCode" class="text-danger"></span>
|
<span asp-validation-for="InviteCode" class="text-danger"></span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
|
|
||||||
@if (await BreezService.Get(storeId) is not null)
|
|
||||||
{
|
|
||||||
<button name="command" type="submit" value="clear" class="btn btn-danger">Clear</button>
|
|
||||||
|
|
||||||
var client = BreezService.GetClient(storeId);
|
<input type="hidden" asp-for="PaymentKey"/>
|
||||||
if (client is not null)
|
|
||||||
{
|
|
||||||
<pre>
|
|
||||||
@Json.Serialize(client.Sdk.NodeInfo())
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
15
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/Info.cshtml
Normal file
15
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/Info.cshtml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@model object
|
||||||
|
@{
|
||||||
|
var storeId = Model switch
|
||||||
|
{
|
||||||
|
string s => s,
|
||||||
|
StoreDashboardViewModel dashboardModel => dashboardModel.StoreId,
|
||||||
|
_ => Context.GetImplicitStoreId()
|
||||||
|
};
|
||||||
|
ViewData.SetActivePage("Breez", "Create Swapin Refund", "Info");
|
||||||
|
|
||||||
|
}
|
||||||
|
<partial name="Breez/BreezNodeInfo" model="@storeId"/>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
@using BTCPayServer.Components
|
||||||
|
@using BTCPayServer
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@model BTCPayServer.Plugins.Breez.PaymentsViewModel
|
||||||
|
@{
|
||||||
|
var storeId = Context.GetCurrentStoreId();
|
||||||
|
|
||||||
|
ViewData.SetActivePage("Breez", "Payments", "Payments");
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Send</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Receive</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<partial name="Breez/BreezPaymentsTable" model="Model.Payments"/>
|
||||||
|
<vc:pager view-model="Model"></vc:pager>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
193
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml
Normal file
193
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
@using Breez.Sdk
|
||||||
|
@using BTCPayServer
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
|
@using BTCPayServer.Components.QRCode
|
||||||
|
@using BTCPayServer.Components.TruncateCenter
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Payments
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@using NBitcoin
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||||
|
@{
|
||||||
|
ViewData.SetActivePage("Breez", "Swap In", "SwapIn");
|
||||||
|
string storeId = Model switch
|
||||||
|
{
|
||||||
|
string s => s,
|
||||||
|
StoreDashboardViewModel dashboardModel => dashboardModel.StoreId,
|
||||||
|
_ => Context.GetImplicitStoreId()
|
||||||
|
};
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
if (sdk is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var inProgressSwap = sdk.InProgressSwap();
|
||||||
|
var refundables = sdk.ListRefundables();
|
||||||
|
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||||
|
var ni = sdk.NodeInfo();
|
||||||
|
var f = sdk.RecommendedFees();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<datalist id="fees">
|
||||||
|
<option value="@f.fastestFee">Fastest fee</option>
|
||||||
|
<option value="@f.halfHourFee">Half hour fee</option>
|
||||||
|
<option value="@f.hourFee">Hour fee</option>
|
||||||
|
<option value="@f.economyFee">Economic fee</option>
|
||||||
|
<option value="@f.minimumFee">Minimum fee</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
@if (inProgressSwap is null)
|
||||||
|
{
|
||||||
|
<a class="btn btn-primary" asp-action="SwapInCreate" asp-controller="Breez" asp-route-storeId="@storeId">Create</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (inProgressSwap is not null)
|
||||||
|
{
|
||||||
|
<div class="payment-box">
|
||||||
|
<div class="qr-container" data-clipboard="@inProgressSwap.bitcoinAddress">
|
||||||
|
<vc:qr-code data="@inProgressSwap.bitcoinAddress"/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group mt-3">
|
||||||
|
<div class="form-floating">
|
||||||
|
<vc:truncate-center text="@inProgressSwap.bitcoinAddress" padding="15" elastic="true" classes="form-control-plaintext" id="Address"/>
|
||||||
|
<label for="Address">Address</label>
|
||||||
|
</div>
|
||||||
|
<span class="">Please send an amount between @Money.Satoshis(inProgressSwap.minAllowedDeposit).ToDecimal(MoneyUnit.BTC) BTC and @Money.Satoshis(inProgressSwap.maxAllowedDeposit).ToDecimal(MoneyUnit.BTC) </span>
|
||||||
|
@if (deriv is not null)
|
||||||
|
{
|
||||||
|
<a class="btn btn-primary" asp-controller="UIWallets" asp-action="WalletSend" asp-route-walletId="@Model.WalletId" asp-route-defaultDestination="@inProgressSwap.bitcoinAddress">Send using BTCPay Wallet</a>
|
||||||
|
}
|
||||||
|
@{
|
||||||
|
var onChainSats = ni.onchainBalanceMsat / 1000;
|
||||||
|
if (inProgressSwap.minAllowedDeposit <= (long) onChainSats)
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<form asp-action="Sweep" asp-route-storeId="@storeId">
|
||||||
|
<input type="hidden" value="@inProgressSwap.bitcoinAddress" name="address"/>
|
||||||
|
<button type="submit"> Sweep onchain funds to swap in</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (inProgressSwap.unconfirmedSats + inProgressSwap.confirmedSats + inProgressSwap.paidSats > 0)
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
<span class="text-nowrap">@inProgressSwap.unconfirmedSats sats unconfirmed</span>
|
||||||
|
<span class="text-nowrap">@inProgressSwap.confirmedSats sats confirmed</span>
|
||||||
|
<span class="text-nowrap">@inProgressSwap.paidSats sats paid</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (inProgressSwap.unconfirmedTxIds.Any())
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
|
||||||
|
<span class="text-nowrap">Unconfirmed transactions</span>
|
||||||
|
@foreach (var txId in inProgressSwap.unconfirmedTxIds)
|
||||||
|
{
|
||||||
|
<vc:truncate-center text="@txId" link="@BitcoinPaymentType.Instance.GetTransactionLink(BtcPayNetworkProvider.BTC, txId)" classes="truncate-center-id"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (inProgressSwap.confirmedTxIds.Any())
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
|
||||||
|
<span class="text-nowrap">Confirmed transactions</span>
|
||||||
|
@foreach (var txId in inProgressSwap.confirmedTxIds)
|
||||||
|
{
|
||||||
|
<vc:truncate-center text="@txId" link="@BitcoinPaymentType.Instance.GetTransactionLink(BtcPayNetworkProvider.BTC, txId)" classes="truncate-center-id"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (refundables?.Any() is true)
|
||||||
|
{
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Deposit Address</th>
|
||||||
|
<th>Payment</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var refund in refundables)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@refund.status</td>
|
||||||
|
<td>@DateTimeOffset.FromUnixTimeSeconds(refund.createdAt)</td>
|
||||||
|
<td>@refund.bitcoinAddress</td>
|
||||||
|
<td>
|
||||||
|
@if (refund.unconfirmedSats + refund.confirmedSats + refund.paidSats > 0)
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
<span class="text-nowrap">@refund.unconfirmedSats sats unconfirmed</span>
|
||||||
|
<span class="text-nowrap">@refund.confirmedSats sats confirmed</span>
|
||||||
|
<span class="text-nowrap">@refund.paidSats sats paid</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (refund.unconfirmedTxIds.Any())
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
|
||||||
|
<span class="text-nowrap">Unconfirmed transactions</span>
|
||||||
|
@foreach (var txId in refund.unconfirmedTxIds)
|
||||||
|
{
|
||||||
|
<vc:truncate-center text="@txId" link="@BitcoinPaymentType.Instance.GetTransactionLink(BtcPayNetworkProvider.BTC, txId)" classes="truncate-center-id"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (refund.confirmedTxIds.Any())
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
|
||||||
|
<span class="text-nowrap">Confirmed transactions</span>
|
||||||
|
@foreach (var txId in refund.confirmedTxIds)
|
||||||
|
{
|
||||||
|
<vc:truncate-center text="@txId" link="@BitcoinPaymentType.Instance.GetTransactionLink(BtcPayNetworkProvider.BTC, txId)" classes="truncate-center-id"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (refund.refundTxIds.Any())
|
||||||
|
{
|
||||||
|
<div class="card truncate-center-id">
|
||||||
|
|
||||||
|
<span class="text-nowrap">Refund transactions</span>
|
||||||
|
@foreach (var txId in refund.refundTxIds)
|
||||||
|
{
|
||||||
|
<vc:truncate-center text="@txId" link="@BitcoinPaymentType.Instance.GetTransactionLink(BtcPayNetworkProvider.BTC, txId)" classes="truncate-center-id"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-link" asp-controller="Breez" asp-action="SwapInRefund" asp-route-storeId="@storeId" asp-route-address="@refund.bitcoinAddress">Start Refund</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@using Microsoft.AspNetCore.Routing
|
||||||
|
@model string
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@{
|
||||||
|
var storeId = Context.GetImplicitStoreId();
|
||||||
|
var address = Context.GetRouteValue("address").ToString();
|
||||||
|
ViewData.SetActivePage("Breez", "Create Swapin Refund", "SwapIn");
|
||||||
|
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
var f = sdk.RecommendedFees();
|
||||||
|
}
|
||||||
|
|
||||||
|
<datalist id="fees">
|
||||||
|
<option value="@f.fastestFee">Fastest fee</option>
|
||||||
|
<option value="@f.halfHourFee">Half hour fee</option>
|
||||||
|
<option value="@f.hourFee">Hour fee</option>
|
||||||
|
<option value="@f.economyFee">Economic fee</option>
|
||||||
|
<option value="@f.minimumFee">Minimum fee</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" asp-action="SwapInRefund" asp-route-storeId="@storeId" asp-route-address="@address">
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
<a href="https://docs.btcpayserver.org/Forms" target="_blank" rel="noreferrer noopener" title="More information...">
|
||||||
|
<vc:icon symbol="info"/>
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="refundAddress" class="form-label" data-required>Refund address</label>
|
||||||
|
<input type="text" id="refundAddress" name="refundAddress" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="satPerByte" class="form-label" data-required>Fees</label>
|
||||||
|
<input type="number" min="@f.minimumFee" list="satPerByte" id="satPerByte" name="satPerByte" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
103
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapOut.cshtml
Normal file
103
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapOut.cshtml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
@using Breez.Sdk
|
||||||
|
@using BTCPayServer
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||||
|
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
ViewData.SetActivePage("Breez", "Swap Out", "SwapOut");
|
||||||
|
string storeId = null;
|
||||||
|
if (Model is string s)
|
||||||
|
{
|
||||||
|
storeId = s;
|
||||||
|
}
|
||||||
|
else if (Model is StoreDashboardViewModel dashboardModel)
|
||||||
|
{
|
||||||
|
storeId = dashboardModel.StoreId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
storeId = Context.GetImplicitStoreId();
|
||||||
|
}
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
if (sdk is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var inProgressSwaps = sdk.InProgressReverseSwaps();
|
||||||
|
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||||
|
var f = sdk.RecommendedFees();
|
||||||
|
var swapOutRec = sdk.FetchReverseSwapFees(new ReverseSwapFeesRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
<datalist id="fees">
|
||||||
|
<option value="@f.fastestFee">Fastest fee</option>
|
||||||
|
<option value="@f.halfHourFee">Half hour fee</option>
|
||||||
|
<option value="@f.hourFee">Hour fee</option>
|
||||||
|
<option value="@f.economyFee">Economic fee</option>
|
||||||
|
<option value="@f.minimumFee">Minimum fee</option>
|
||||||
|
</datalist>
|
||||||
|
<datalist list="addresses">
|
||||||
|
@if (deriv is not null)
|
||||||
|
{
|
||||||
|
<option value="store"> Store wallet</option>
|
||||||
|
}
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<form method="post" asp-action="SwapOut" asp-route-storeId="@storeId">
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="address" class="form-label" data-required>Address</label>
|
||||||
|
<input type="text" id="address" name="address" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="satPerByte" class="form-label" data-required>Refund address</label>
|
||||||
|
<input type="number" min="@f.minimumFee" list="satPerByte" id="satPerByte" name="satPerByte" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="amount" class="form-label" data-required>Amount (sats)</label>
|
||||||
|
<input type="number" min="@swapOutRec.min" max="@swapOutRec.max" id="amount" name="amount" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="feesHash" value="@swapOutRec.feesHash"/>
|
||||||
|
|
||||||
|
|
||||||
|
@if (inProgressSwaps?.Any() is true)
|
||||||
|
{
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var swap in inProgressSwaps)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@swap.id</td>
|
||||||
|
<td>@swap.status</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
67
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/Sweep.cshtml
Normal file
67
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/Sweep.cshtml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
@using BTCPayServer
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@model string
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||||
|
@{
|
||||||
|
var storeId = Context.GetImplicitStoreId();
|
||||||
|
Layout = "_Layout";
|
||||||
|
ViewData.SetActivePage("Breez", "Sweep", "Sweep");
|
||||||
|
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
var f = sdk.RecommendedFees();
|
||||||
|
var info = sdk.NodeInfo();
|
||||||
|
|
||||||
|
|
||||||
|
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||||
|
|
||||||
|
}
|
||||||
|
<datalist list="addresses">
|
||||||
|
@if (deriv is not null)
|
||||||
|
{
|
||||||
|
<option value="store"> Store wallet</option>
|
||||||
|
}
|
||||||
|
</datalist>
|
||||||
|
<datalist id="fees">
|
||||||
|
<option value="@f.fastestFee">Fastest fee</option>
|
||||||
|
<option value="@f.halfHourFee">Half hour fee</option>
|
||||||
|
<option value="@f.hourFee">Hour fee</option>
|
||||||
|
<option value="@f.economyFee">Economic fee</option>
|
||||||
|
<option value="@f.minimumFee">Minimum fee</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<form method="post" asp-action="Sweep" asp-route-storeId="@storeId">
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
<span>@ViewData["Title"]</span>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="address" class="form-label" data-required>address</label>
|
||||||
|
<input type="text" list="addresses" id="address" name="address" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="satPerByte" class="form-label" data-required>Fees</label>
|
||||||
|
<input type="number" min="@f.minimumFee" list="satPerByte" id="satPerByte" name="satPerByte" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Create</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section PageFootContent {
|
||||||
|
<partial name="_ValidationScriptsPartial"/>
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@{
|
||||||
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
|
ViewData["NavPartialName"] = "_Nav";
|
||||||
|
}
|
||||||
|
@RenderBody()
|
||||||
33
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/_Nav.cshtml
Normal file
33
Plugins/BTCPayServer.Plugins.Breez/Views/Breez/_Nav.cshtml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@{
|
||||||
|
var storeId = Model switch
|
||||||
|
{
|
||||||
|
string s => s,
|
||||||
|
StoreDashboardViewModel dashboardModel => dashboardModel.StoreId,
|
||||||
|
_ => Context.GetImplicitStoreId()
|
||||||
|
};
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="sticky-header-setup"></div>
|
||||||
|
<div class="sticky-header mb-l">
|
||||||
|
<h2 class="mt-1 mb-2 mb-lg-4">Breez</h2>
|
||||||
|
<nav id="SectionNav">
|
||||||
|
<div class="nav">
|
||||||
|
@if (sdk is not null)
|
||||||
|
{
|
||||||
|
<a asp-action="Info" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Info")">Info</a>
|
||||||
|
<a asp-action="Payments" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Payments")">Payments</a>
|
||||||
|
<a asp-action="SwapIn" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapIn")">Swap Ins</a>
|
||||||
|
<a asp-action="SwapOut" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapOut")">Swap Outs</a>
|
||||||
|
}
|
||||||
|
<a asp-action="Configure" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Configure")">Configuration</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
@using BTCPayServer.Lightning
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@{
|
||||||
|
string storeId = null;
|
||||||
|
if (Model is string s)
|
||||||
|
{
|
||||||
|
storeId = s;
|
||||||
|
}
|
||||||
|
else if (Model is StoreDashboardViewModel dashboardModel)
|
||||||
|
{
|
||||||
|
storeId = dashboardModel.StoreId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
storeId = Context.GetImplicitStoreId();
|
||||||
|
}
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
if (sdk is null)
|
||||||
|
return;
|
||||||
|
var nodeState = sdk.NodeInfo();
|
||||||
|
var lspInfo = sdk.LspInfo();
|
||||||
|
}
|
||||||
|
<div class="widget store-numbers" id="Breez-Info" style="grid-column-start: 1; grid-column-end: 4;">
|
||||||
|
@if (Model is StoreDashboardViewModel)
|
||||||
|
{
|
||||||
|
<header>
|
||||||
|
<h4>Breez Node</h4>
|
||||||
|
<a asp-action="Info" asp-controller="Breez" asp-route-storeId="@storeId">
|
||||||
|
Manage
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
}
|
||||||
|
<div class="d-flex w-100 align-items-center justify-content-start gap-3">
|
||||||
|
<span class="btcpay-status btcpay-status--enabled"></span>
|
||||||
|
<h6 class="text-truncate">@nodeState.id</h6>
|
||||||
|
</div>
|
||||||
|
@if (lspInfo is not null)
|
||||||
|
{
|
||||||
|
<div class="d-flex w-100 align-items-center justify-content-start gap-3">
|
||||||
|
<span class="btcpay-status btcpay-status--enabled"></span>
|
||||||
|
<h6 class="text-truncate">@lspInfo.name connected</h6>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="store-number">
|
||||||
|
<header>
|
||||||
|
<h6>On-Chain Balance</h6>
|
||||||
|
@if (Model is StoreDashboardViewModel && nodeState.onchainBalanceMsat > 0)
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<a asp-action="Sweep" asp-controller="Breez" asp-route-storeId="@storeId">Sweep</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</header>
|
||||||
|
<div class="balance d-flex align-items-baseline gap-1">
|
||||||
|
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.onchainBalanceMsat)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.onchainBalanceMsat)</h3>
|
||||||
|
<span class="text-secondary fw-semibold currency">BTC</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="store-number">
|
||||||
|
<header>
|
||||||
|
<h6>Lightning Balance</h6>
|
||||||
|
@if (Model is StoreDashboardViewModel)
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<a asp-action="SwapIn" asp-controller="Breez" asp-route-storeId="@storeId">Swap in</a>
|
||||||
|
@if (nodeState.channelsBalanceMsat > 0)
|
||||||
|
{
|
||||||
|
<span> - </span>
|
||||||
|
<a asp-action="SwapOut" asp-controller="Breez" asp-route-storeId="@storeId">Swap out</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</header>
|
||||||
|
<div class="balance d-flex align-items-baseline gap-1">
|
||||||
|
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.channelsBalanceMsat)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.channelsBalanceMsat)</h3>
|
||||||
|
<span class="text-secondary fw-semibold currency">BTC</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="store-number">
|
||||||
|
<header>
|
||||||
|
<h6>Lightning insight</h6>
|
||||||
|
</header>
|
||||||
|
<div class="balance d-flex align-items-baseline gap-1">
|
||||||
|
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.maxReceivableMsat)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.maxReceivableMsat)</h3>
|
||||||
|
<span class="text-secondary fw-semibold currency">BTC receivable</span>
|
||||||
|
</div>
|
||||||
|
<div class="balance d-flex align-items-baseline gap-1">
|
||||||
|
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.maxPayableMsat)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.maxPayableMsat)</h3>
|
||||||
|
<span class="text-secondary fw-semibold currency">BTC spendable</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
@using Breez.Sdk
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Lightning
|
||||||
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@using BTCPayServer.Plugins.Breez
|
||||||
|
@using BTCPayServer.Security
|
||||||
|
@model object
|
||||||
|
@inject BreezService BreezService
|
||||||
|
@{
|
||||||
|
var data = Model as List<Payment>;
|
||||||
|
var storeId = Context.GetImplicitStoreId();
|
||||||
|
if (data is null)
|
||||||
|
{
|
||||||
|
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||||
|
if (sdk is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data = sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.ALL, null, null, null, 0, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDashboard = Model is StoreDashboardViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="@(isDashboard ? "widget store-wallet-balance" : "")" style="@(isDashboard ? "grid-column-start: 4;grid-column-end: 13;" : "")">
|
||||||
|
@if (isDashboard)
|
||||||
|
{
|
||||||
|
<header>
|
||||||
|
<h3>Breez Payments</h3>
|
||||||
|
@if (data.Any())
|
||||||
|
{
|
||||||
|
<a asp-controller="Breez" asp-action="Payments" asp-route-storeId="@storeId">View All</a>
|
||||||
|
}
|
||||||
|
</header>
|
||||||
|
}
|
||||||
|
@if (!data.Any())
|
||||||
|
{
|
||||||
|
<p class="text-secondary mt-3 mb-0">
|
||||||
|
There are no recent payments.
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-125px">Id</th>
|
||||||
|
<th class="w-125px">Timestamp</th>
|
||||||
|
<th class="w-125px">Type</th>
|
||||||
|
<th class="w-125px">Amount</th>
|
||||||
|
<th class="text-nowrap">Fee</th>
|
||||||
|
<th class="text-nowrap">Status</th>
|
||||||
|
<th class="text-nowrap">Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var payment in data)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
<span class="text-break">@payment.id</span>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">@DateTimeOffset.FromUnixTimeSeconds(payment.paymentTime).ToTimeAgo()</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">>@payment.paymentType.ToString().ToLowerInvariant().Replace("_", " ")</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">>@LightMoney.MilliSatoshis(payment.amountMsat).ToDecimal(LightMoneyUnit.BTC) BTC</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">>@LightMoney.MilliSatoshis(payment.feeMsat).ToDecimal(LightMoneyUnit.BTC) BTC</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">@payment.status.ToString().ToLowerInvariant()</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-break">@payment.description</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a asp-action="Index" asp-controller="Breez" asp-route-storeId="@storeId">Breez needs to be configured beforehand.</a>
|
<a asp-action="Configure" asp-controller="Breez" asp-route-storeId="@storeId">Breez needs to be configured beforehand.</a>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -26,22 +26,11 @@
|
|||||||
const typePrefix = 'type=breez;store=@Model.StoreId';
|
const typePrefix = 'type=breez;store=@Model.StoreId';
|
||||||
const triggerEl = document.getElementById('LightningNodeType-Breez')
|
const triggerEl = document.getElementById('LightningNodeType-Breez')
|
||||||
const connStringEl = document.getElementById('ConnectionString')
|
const connStringEl = document.getElementById('ConnectionString')
|
||||||
|
const connString = connStringEl.value;
|
||||||
const isBreez = connString.startsWith(typePrefix);
|
const isBreez = connString.startsWith(typePrefix);
|
||||||
const setWallet = accessKey => connStringEl.value = accessKey.length
|
|
||||||
? `${typePrefix};`
|
|
||||||
: ''
|
|
||||||
|
|
||||||
if (isBreez) {
|
if (isBreez) {
|
||||||
if (apiToken) {
|
|
||||||
walletEl.value = apiToken
|
|
||||||
} else if (walletId) {
|
|
||||||
const optionEl = document.querySelector(`option[data-wallet-id="${walletId}"]`)
|
|
||||||
if (optionEl) {
|
|
||||||
const accessKey = optionEl.getAttribute('value')
|
|
||||||
walletEl.value = accessKey
|
|
||||||
setWallet(accessKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// deactivate currently active tab and activate Breez tab
|
// deactivate currently active tab and activate Breez tab
|
||||||
const activeEl = document.querySelector('input[name="LightningNodeType"]:checked')
|
const activeEl = document.querySelector('input[name="LightningNodeType"]:checked')
|
||||||
@@ -52,6 +41,7 @@
|
|||||||
triggerEl.setAttribute('checked', 'checked')
|
triggerEl.setAttribute('checked', 'checked')
|
||||||
triggerEl.setAttribute('aria-selected', 'true')
|
triggerEl.setAttribute('aria-selected', 'true')
|
||||||
document.getElementById('BreezSetup').classList.add('active', 'show')
|
document.getElementById('BreezSetup').classList.add('active', 'show')
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +52,13 @@
|
|||||||
tabTrigger.show()
|
tabTrigger.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate('change', '#BreezWallet', e => {
|
delegate('change', 'input[name="LightningNodeType"]', e => {
|
||||||
const { value } = e.target
|
|
||||||
setWallet(value)
|
const activeEl = document.querySelector('input[name="LightningNodeType"]:checked')
|
||||||
const tabTrigger = new bootstrap.Tab(triggerEl)
|
if (activeEl.id === "LightningNodeType-Breez"){
|
||||||
triggerEl.checked = true
|
connStringEl.value =typePrefix;
|
||||||
tabTrigger.show()
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user