diff --git a/Plugins/BTCPayServer.Plugins.Prism/BTCPayServer.Plugins.Prism.csproj b/Plugins/BTCPayServer.Plugins.Prism/BTCPayServer.Plugins.Prism.csproj index 81f887a..78a2df7 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/BTCPayServer.Plugins.Prism.csproj +++ b/Plugins/BTCPayServer.Plugins.Prism/BTCPayServer.Plugins.Prism.csproj @@ -11,7 +11,7 @@ Prism Automated value splits for Bitcoin. - 1.2.4 + 1.2.5 true diff --git a/Plugins/BTCPayServer.Plugins.Prism/Components/PrismDestinationEditor.razor b/Plugins/BTCPayServer.Plugins.Prism/Components/PrismDestinationEditor.razor index 3843c19..3734a7e 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/Components/PrismDestinationEditor.razor +++ b/Plugins/BTCPayServer.Plugins.Prism/Components/PrismDestinationEditor.razor @@ -13,7 +13,7 @@ {
- + @if (Invalid) { Invalid diff --git a/Plugins/BTCPayServer.Plugins.Prism/Components/PrismEdit.razor b/Plugins/BTCPayServer.Plugins.Prism/Components/PrismEdit.razor index d5ede49..9fc08a7 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/Components/PrismEdit.razor +++ b/Plugins/BTCPayServer.Plugins.Prism/Components/PrismEdit.razor @@ -4,12 +4,16 @@ @using BTCPayServer.HostedServices @using BTCPayServer.Payments @using BTCPayServer.PayoutProcessors +@using BTCPayServer.Services.Custodian.Client @using Microsoft.AspNetCore.Http @using Microsoft.AspNetCore.Routing @using Microsoft.Extensions.Logging @using NBitcoin @using LightningAddressData = BTCPayServer.Data.LightningAddressData @using MarkPayoutRequest = BTCPayServer.HostedServices.MarkPayoutRequest +@using System.Collections +@using BTCPayServer.Abstractions.Custodians +@using BTCPayServer.Abstractions.Extensions @inject IPluginHookService PluginHookService @inject LightningAddressService LightningAddressService @inject PayoutProcessorService PayoutProcessorService @@ -18,6 +22,8 @@ @inject LinkGenerator LinkGenerator @inject PullPaymentHostedService PullPaymentHostedService @inject IHttpContextAccessor HttpContextAccessor +@inject CustodianAccountRepository CustodianAccountRepository +@inject IEnumerable Custodians @inject ILogger Logger @implements IDisposable @@ -41,6 +47,10 @@ else { } + @foreach (var destination in CustodianDestinations) + { + + } @@ -205,6 +215,7 @@ else public PaymentMethodId pmichain { get; set; } = new("BTC", PaymentTypes.BTCLike); public bool NoPayoutProcessors { get; set; } + public Dictionary CustodianDestinations { get; set; } private string PrismEditButtonsFilter { get; set; } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -236,6 +247,35 @@ else await Task.WhenAll(tasks); Settings = await fetchSettings; Users = await fetchLnAddresses; + CustodianDestinations = await FetchCustodians(); + + async Task> FetchCustodians() + { + var result = new Dictionary(); + var custodianConfigs = await CustodianAccountRepository.FindByStoreId(StoreId); + foreach (var custodianConfig in custodianConfigs) + { + var custodian = Custodians.GetCustodianByCode(custodianConfig.CustodianCode); + if(custodian is not ICanDeposit canDeposit) + continue; + foreach (var depositablePaymentMethod in canDeposit.GetDepositablePaymentMethods()) + { + var pmi = PaymentMethodId.TryParse(depositablePaymentMethod); + if(pmi is null || pmi.CryptoCode != "BTC") + continue; + + var custodianDestination = new CustodianDestinationValidator.CustodianDestination() + { + CustodianId = custodianConfig.Id, + PaymentMethod = pmi.ToString() + }; + result.TryAdd(custodianDestination.ToString(), $"{custodianConfig.Name} {pmi.ToPrettyString()} (Custodian)"); + } + + } + return result; + } + EditContext = new EditContext(Settings); MessageStore = new ValidationMessageStore(EditContext); EditContext.OnValidationRequested += Validate; @@ -252,6 +292,7 @@ else await base.OnAfterRenderAsync(firstRender); } + private void FieldChanged(object sender, FieldChangedEventArgs e) { StatusMessageModel = null; diff --git a/Plugins/BTCPayServer.Plugins.Prism/CustodianDestinationValidator.cs b/Plugins/BTCPayServer.Plugins.Prism/CustodianDestinationValidator.cs new file mode 100644 index 0000000..81f30a2 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Prism/CustodianDestinationValidator.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Abstractions.Custodians; +using BTCPayServer.Abstractions.Extensions; +using BTCPayServer.Data; +using BTCPayServer.Payments; +using BTCPayServer.Services.Custodian.Client; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; + +namespace BTCPayServer.Plugins.Prism; + +public class CustodianDestinationValidator : IPluginHookFilter +{ + private readonly IServiceProvider _serviceProvider; + public string Hook => "prism-destination-validate"; + + public CustodianDestinationValidator(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public async Task Execute(object args) + { + var result = new PrismDestinationValidationResult(); + if (args is not string args1 || !args1.StartsWith("custodian:")) return args; + + try + { + var custodianDestination = + JObject.Parse(args1.Substring("custodian:".Length)).ToObject(); + var custodianPaymentMethod = custodianDestination.PaymentMethod is null + ? new PaymentMethodId("BTC", PaymentTypes.LightningLike) + : PaymentMethodId.Parse(custodianDestination.PaymentMethod); + + result.PaymentMethod = custodianPaymentMethod; + await using var ctx = _serviceProvider.GetService().CreateContext(); + var custodianAccountData = ctx.CustodianAccount.SingleOrDefault(data => data.Id == custodianDestination.CustodianId); + if (custodianAccountData is null) + { + result.Success = false; + return result; + } + + var custdodian = _serviceProvider.GetServices().GetCustodianByCode(custodianAccountData.CustodianCode); + if (custdodian is null) + { + result.Success = false; + return result; + } + + if (custdodian is ICanDeposit canDeposit && + canDeposit.GetDepositablePaymentMethods() is { } paymentMethods && + paymentMethods.Any(s => PaymentMethodId.TryParse(s) == custodianPaymentMethod)) + { + result.Success = true; + return result; + } + + result.Success = false; + return result; + } + catch (Exception e) + { + result.Success = false; + return result; + } + } + + + public class CustodianDestination + { + public string CustodianId { get; set; } + public string PaymentMethod { get; set; } + + override public string ToString() + { + return $"custodian:{JObject.FromObject(this)}"; + } + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Prism/CustodianPrismClaimCreate.cs b/Plugins/BTCPayServer.Plugins.Prism/CustodianPrismClaimCreate.cs new file mode 100644 index 0000000..474a45f --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Prism/CustodianPrismClaimCreate.cs @@ -0,0 +1,104 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Abstractions.Custodians; +using BTCPayServer.Abstractions.Extensions; +using BTCPayServer.Data; +using BTCPayServer.HostedServices; +using BTCPayServer.Payments; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; + +namespace BTCPayServer.Plugins.Prism; + +public class CustodianPrismClaimCreate : IPluginHookFilter +{ + private readonly IServiceProvider _serviceProvider; + public string Hook => "prism-claim-create"; + + public CustodianPrismClaimCreate(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public async Task Execute(object args) + { + if (args is not ClaimRequest claimRequest) + { + return args; + } + + if (claimRequest.Destination?.ToString() is not { } args1 || !args1.StartsWith("custodian:")) return args; + + try + { + + var custodianDestination = JObject.Parse(args1.Substring("custodian:".Length)) + .ToObject(); + var custodianPaymentMethod = custodianDestination.PaymentMethod is null + ? new PaymentMethodId("BTC", PaymentTypes.LightningLike) + : PaymentMethodId.Parse(custodianDestination.PaymentMethod); + + await using var ctx = _serviceProvider.GetRequiredService().CreateContext(); + var custodianAccountData = await ctx.CustodianAccount.SingleOrDefaultAsync(data => data.Id == custodianDestination.CustodianId); + if (custodianAccountData is null) + { + return null; + } + + var custdodian = _serviceProvider.GetServices().GetCustodianByCode(custodianAccountData.CustodianCode); + if (custdodian is null) + { + return null; + } + + if (custdodian is not ICanDeposit canDeposit || + canDeposit.GetDepositablePaymentMethods() is { } paymentMethods && + paymentMethods.Any(s => PaymentMethodId.TryParse(s) == custodianPaymentMethod)) + { + return null; + } + + var handler = _serviceProvider.GetServices().FindPayoutHandler(custodianPaymentMethod); + if (handler is null) + { + return null; + } + + var config = custodianAccountData.GetBlob(); + config["depositAddressConfig"] = JToken.FromObject(new + { + amount = claimRequest.Value + }); + var depositAddressAsync = + await canDeposit.GetDepositAddressAsync(custodianPaymentMethod.ToString(),config, CancellationToken.None); + if (depositAddressAsync.Address is null) + { + return null; + } + + var claimDestination = await handler.ParseClaimDestination(custodianPaymentMethod, + depositAddressAsync.Address, CancellationToken.None); + if (claimDestination.destination is null) + { + + return null; + } + + + claimRequest.Destination = claimDestination.destination; + claimRequest.PaymentMethodId = custodianPaymentMethod; + + return claimRequest; + + } + catch (Exception e) + { + + return null; + } + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Prism/OnChainPrismClaimCreate.cs b/Plugins/BTCPayServer.Plugins.Prism/OnChainPrismClaimCreate.cs index c98d17f..e4be702 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/OnChainPrismClaimCreate.cs +++ b/Plugins/BTCPayServer.Plugins.Prism/OnChainPrismClaimCreate.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Threading.Tasks; using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Data; diff --git a/Plugins/BTCPayServer.Plugins.Prism/PrismPlugin.cs b/Plugins/BTCPayServer.Plugins.Prism/PrismPlugin.cs index 93778b5..c42ede0 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/PrismPlugin.cs +++ b/Plugins/BTCPayServer.Plugins.Prism/PrismPlugin.cs @@ -22,10 +22,12 @@ public class PrismPlugin : BaseBTCPayServerPlugin "store-integrations-nav")); applicationBuilder.AddSingleton(); applicationBuilder.AddHostedService(provider => provider.GetRequiredService()); + applicationBuilder.AddSingleton(); applicationBuilder.AddSingleton(); applicationBuilder.AddSingleton(); applicationBuilder.AddSingleton(); applicationBuilder.AddSingleton(); + applicationBuilder.AddSingleton(); base.Execute(applicationBuilder); }