diff --git a/BTCPayServer.Tests/Extensions.cs b/BTCPayServer.Tests/Extensions.cs index 8ad062e36..32ab4928b 100644 --- a/BTCPayServer.Tests/Extensions.cs +++ b/BTCPayServer.Tests/Extensions.cs @@ -2,8 +2,11 @@ using System; using System.Text; using System.Threading; using System.Threading.Tasks; +using BTCPayServer.Services.Wallets; using BTCPayServer.Tests.Logging; using Microsoft.AspNetCore.Mvc; +using NBXplorer.DerivationStrategy; +using NBXplorer.Models; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using OpenQA.Selenium; @@ -15,6 +18,10 @@ namespace BTCPayServer.Tests { public static class Extensions { + public static Task ReserveAddressAsync(this BTCPayWallet wallet, DerivationStrategyBase derivationStrategyBase) + { + return wallet.ReserveAddressAsync(null, derivationStrategyBase, "test"); + } private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; public static string ToJson(this object o) => JsonConvert.SerializeObject(o, Formatting.None, JsonSettings); diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 81567503c..f1f17bb2b 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -1935,6 +1935,9 @@ namespace BTCPayServer.Tests RedirectURL = "http://toto.com/lol" } }); + var invoiceObject = await client.GetOnChainWalletObject(user.StoreId, "BTC", new OnChainWalletObjectId("invoice", newInvoice.Id), false); + Assert.Contains(invoiceObject.Links.Select(l => l.Type), t => t == "script"); + Assert.EndsWith($"/i/{newInvoice.Id}", newInvoice.CheckoutLink); var controller = tester.PayTester.GetController(user.UserId, user.StoreId); var model = (PaymentModel)((ViewResult)await controller.Checkout(newInvoice.Id)).Model; @@ -1968,11 +1971,18 @@ namespace BTCPayServer.Tests Assert.True(store.LazyPaymentMethods); invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest() { Amount = 1, Currency = "USD" }); + invoiceObject = await client.GetOnChainWalletObject(user.StoreId, "BTC", new OnChainWalletObjectId("invoice", invoice.Id), false); + Assert.DoesNotContain(invoiceObject.Links.Select(l => l.Type), t => t == "script"); + + paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id); Assert.Single(paymentMethods); Assert.False(paymentMethods.First().Activated); await client.ActivateInvoicePaymentMethod(user.StoreId, invoice.Id, paymentMethods.First().PaymentMethod); + invoiceObject = await client.GetOnChainWalletObject(user.StoreId, "BTC", new OnChainWalletObjectId("invoice", invoice.Id), false); + Assert.Contains(invoiceObject.Links.Select(l => l.Type), t => t == "script"); + paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id); Assert.Single(paymentMethods); Assert.True(paymentMethods.First().Activated); @@ -2030,12 +2040,16 @@ namespace BTCPayServer.Tests BitcoinAddress.Create(pm.Destination, tester.ExplorerClient.Network.NBitcoinNetwork), new Money(0.0002m, MoneyUnit.BTC)); }); + await TestUtils.EventuallyAsync(async () => { var pm = Assert.Single(await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id)); Assert.Single(pm.Payments); Assert.Equal(-0.0001m, pm.Due); }); + + invoiceObject = await client.GetOnChainWalletObject(user.StoreId, "BTC", new OnChainWalletObjectId("invoice", invoice.Id), false); + Assert.Contains(invoiceObject.Links.Select(l => l.Type), t => t == "tx"); } [Fact(Timeout = 60 * 20 * 1000)] diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs index bb7a886d1..77594a8d1 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs @@ -34,32 +34,28 @@ namespace BTCPayServer.Controllers.Greenfield private readonly UIInvoiceController _invoiceController; private readonly InvoiceRepository _invoiceRepository; private readonly LinkGenerator _linkGenerator; - private readonly BTCPayNetworkProvider _btcPayNetworkProvider; - private readonly EventAggregator _eventAggregator; - private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary; private readonly CurrencyNameTable _currencyNameTable; private readonly BTCPayNetworkProvider _networkProvider; private readonly PullPaymentHostedService _pullPaymentService; private readonly RateFetcher _rateProvider; + private readonly InvoiceActivator _invoiceActivator; private readonly ApplicationDbContextFactory _dbContextFactory; public LanguageService LanguageService { get; } public GreenfieldInvoiceController(UIInvoiceController invoiceController, InvoiceRepository invoiceRepository, LinkGenerator linkGenerator, LanguageService languageService, BTCPayNetworkProvider btcPayNetworkProvider, - EventAggregator eventAggregator, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, - CurrencyNameTable currencyNameTable, BTCPayNetworkProvider networkProvider, RateFetcher rateProvider, + CurrencyNameTable currencyNameTable, RateFetcher rateProvider, + InvoiceActivator invoiceActivator, PullPaymentHostedService pullPaymentService, ApplicationDbContextFactory dbContextFactory) { _invoiceController = invoiceController; _invoiceRepository = invoiceRepository; _linkGenerator = linkGenerator; - _btcPayNetworkProvider = btcPayNetworkProvider; - _eventAggregator = eventAggregator; - _paymentMethodHandlerDictionary = paymentMethodHandlerDictionary; _currencyNameTable = currencyNameTable; - _networkProvider = networkProvider; + _networkProvider = btcPayNetworkProvider; _rateProvider = rateProvider; + _invoiceActivator = invoiceActivator; _pullPaymentService = pullPaymentService; _dbContextFactory = dbContextFactory; LanguageService = languageService; @@ -342,8 +338,7 @@ namespace BTCPayServer.Controllers.Greenfield if (PaymentMethodId.TryParse(paymentMethod, out var paymentMethodId)) { - await _invoiceRepository.ActivateInvoicePaymentMethod(_eventAggregator, _btcPayNetworkProvider, - _paymentMethodHandlerDictionary, store, invoice, paymentMethodId); + await _invoiceActivator.ActivateInvoicePaymentMethod(paymentMethodId, invoice, store); return Ok(); } ModelState.AddModelError(nameof(paymentMethod), "Invalid payment method"); diff --git a/BTCPayServer/Controllers/UIInvoiceController.UI.cs b/BTCPayServer/Controllers/UIInvoiceController.UI.cs index c9c7afe51..792f60434 100644 --- a/BTCPayServer/Controllers/UIInvoiceController.UI.cs +++ b/BTCPayServer/Controllers/UIInvoiceController.UI.cs @@ -711,8 +711,7 @@ namespace BTCPayServer.Controllers var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails(); if (!paymentMethodDetails.Activated) { - if (await _InvoiceRepository.ActivateInvoicePaymentMethod(_EventAggregator, _NetworkProvider, - _paymentMethodHandlerDictionary, store, invoice, paymentMethod.GetId())) + if (await _invoiceActivator.ActivateInvoicePaymentMethod(paymentMethod.GetId(), invoice, store)) { return await GetInvoiceModel(invoiceId, paymentMethodId, lang); } diff --git a/BTCPayServer/Controllers/UIInvoiceController.cs b/BTCPayServer/Controllers/UIInvoiceController.cs index 92c287911..51eb14c3a 100644 --- a/BTCPayServer/Controllers/UIInvoiceController.cs +++ b/BTCPayServer/Controllers/UIInvoiceController.cs @@ -14,6 +14,7 @@ using BTCPayServer.Logging; using BTCPayServer.Models; using BTCPayServer.Models.PaymentRequestViewModels; using BTCPayServer.Payments; +using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Rating; using BTCPayServer.Security; using BTCPayServer.Services; @@ -27,6 +28,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using NBitcoin; using NBitpayClient; using BitpayCreateInvoiceRequest = BTCPayServer.Models.BitpayCreateInvoiceRequest; using StoreData = BTCPayServer.Data.StoreData; @@ -37,6 +39,7 @@ namespace BTCPayServer.Controllers public partial class UIInvoiceController : Controller { readonly InvoiceRepository _InvoiceRepository; + private readonly WalletRepository _walletRepository; readonly RateFetcher _RateProvider; readonly StoreRepository _StoreRepository; readonly UserManager _UserManager; @@ -49,12 +52,14 @@ namespace BTCPayServer.Controllers private readonly LanguageService _languageService; private readonly ExplorerClientProvider _ExplorerClients; private readonly UIWalletsController _walletsController; + private readonly InvoiceActivator _invoiceActivator; private readonly LinkGenerator _linkGenerator; public WebhookSender WebhookNotificationManager { get; } public UIInvoiceController( InvoiceRepository invoiceRepository, + WalletRepository walletRepository, CurrencyNameTable currencyNameTable, UserManager userManager, RateFetcher rateProvider, @@ -69,11 +74,13 @@ namespace BTCPayServer.Controllers LanguageService languageService, ExplorerClientProvider explorerClients, UIWalletsController walletsController, + InvoiceActivator invoiceActivator, LinkGenerator linkGenerator) { _CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable)); _StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository)); _InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository)); + _walletRepository = walletRepository; _RateProvider = rateProvider ?? throw new ArgumentNullException(nameof(rateProvider)); _UserManager = userManager; _EventAggregator = eventAggregator; @@ -85,6 +92,7 @@ namespace BTCPayServer.Controllers _languageService = languageService; this._ExplorerClients = explorerClients; _walletsController = walletsController; + _invoiceActivator = invoiceActivator; _linkGenerator = linkGenerator; } @@ -368,6 +376,30 @@ namespace BTCPayServer.Controllers using (logs.Measure("Saving invoice")) { entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, additionalSearchTerms); + foreach (var method in paymentMethods) + { + if (method.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod bp) + { + var walletId = new WalletId(store.Id, method.GetId().CryptoCode); + await _walletRepository.EnsureWalletObject(new WalletObjectId( + walletId, + WalletObjectData.Types.Invoice, + entity.Id + )); + if (bp.GetDepositAddress(((BTCPayNetwork)method.Network).NBitcoinNetwork) is BitcoinAddress address) + { + await _walletRepository.EnsureWalletObjectLink( + new WalletObjectId( + walletId, + WalletObjectData.Types.Script, + address.ScriptPubKey.ToHex()), + new WalletObjectId( + walletId, + WalletObjectData.Types.Invoice, + entity.Id)); + } + } + } } _ = Task.Run(async () => { diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index 50383ca73..bc6035d5b 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -432,6 +432,7 @@ namespace BTCPayServer.Hosting services.AddTransient(); // Add application services. services.AddSingleton(); + services.AddSingleton(); //create a simple client which hooks up to the http scope services.AddScoped(); diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs index 0c7d59099..d53add22c 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs @@ -146,7 +146,7 @@ namespace BTCPayServer.Payments.Bitcoin ? null : _FeeRateProviderFactory.CreateFeeProvider(network).GetFeeRateAsync(), ReserveAddress = _WalletProvider.GetWallet(network) - .ReserveAddressAsync(supportedPaymentMethod.AccountDerivation) + .ReserveAddressAsync(store.Id, supportedPaymentMethod.AccountDerivation, "invoice") }; } diff --git a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs index f58c7c800..64832ff7d 100644 --- a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs +++ b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs @@ -420,7 +420,7 @@ namespace BTCPayServer.Payments.Bitcoin btc.GetDepositAddress(wallet.Network.NBitcoinNetwork).ScriptPubKey == paymentData.ScriptPubKey && paymentMethod.Calculate().Due > Money.Zero) { - var address = await wallet.ReserveAddressAsync(strategy); + var address = await wallet.ReserveAddressAsync(invoice.StoreId, strategy, "invoice"); btc.DepositAddress = address.Address.ToString(); btc.KeyPath = address.KeyPath; await _InvoiceRepository.NewPaymentDetails(invoice.Id, btc, wallet.Network); diff --git a/BTCPayServer/Services/InvoiceActivator.cs b/BTCPayServer/Services/InvoiceActivator.cs new file mode 100644 index 000000000..bc1692bad --- /dev/null +++ b/BTCPayServer/Services/InvoiceActivator.cs @@ -0,0 +1,96 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AngleSharp.Dom; +using BTCPayServer.Data; +using BTCPayServer.Events; +using BTCPayServer.Logging; +using BTCPayServer.Payments; +using BTCPayServer.Payments.Bitcoin; +using BTCPayServer.Services.Invoices; +using NBitcoin; + +namespace BTCPayServer.Services +{ + public class InvoiceActivator + { + private readonly InvoiceRepository _invoiceRepository; + private readonly EventAggregator _eventAggregator; + private readonly BTCPayNetworkProvider _btcPayNetworkProvider; + private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary; + private readonly WalletRepository _walletRepository; + + public InvoiceActivator( + InvoiceRepository invoiceRepository, + EventAggregator eventAggregator, + BTCPayNetworkProvider btcPayNetworkProvider, + PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, + WalletRepository walletRepository) + { + _invoiceRepository = invoiceRepository; + _eventAggregator = eventAggregator; + _btcPayNetworkProvider = btcPayNetworkProvider; + _paymentMethodHandlerDictionary = paymentMethodHandlerDictionary; + _walletRepository = walletRepository; + } + public async Task ActivateInvoicePaymentMethod(PaymentMethodId paymentMethodId, InvoiceEntity invoice, StoreData store) + { + if (invoice.GetInvoiceState().Status != InvoiceStatusLegacy.New) + return false; + bool success = false; + var eligibleMethodToActivate = invoice.GetPaymentMethod(paymentMethodId); + if (!eligibleMethodToActivate.GetPaymentMethodDetails().Activated) + { + var payHandler = _paymentMethodHandlerDictionary[paymentMethodId]; + var supportPayMethod = invoice.GetSupportedPaymentMethod() + .Single(method => method.PaymentId == paymentMethodId); + var paymentMethod = invoice.GetPaymentMethod(paymentMethodId); + var network = _btcPayNetworkProvider.GetNetwork(paymentMethodId.CryptoCode); + var prepare = payHandler.PreparePayment(supportPayMethod, store, network); + InvoiceLogs logs = new InvoiceLogs(); + try + { + var pmis = invoice.GetPaymentMethods().Select(method => method.GetId()).ToHashSet(); + logs.Write($"{paymentMethodId}: Activating", InvoiceEventData.EventSeverity.Info); + var newDetails = await + payHandler.CreatePaymentMethodDetails(logs, supportPayMethod, paymentMethod, store, network, + prepare, pmis); + eligibleMethodToActivate.SetPaymentMethodDetails(newDetails); + await _invoiceRepository.UpdateInvoicePaymentMethod(invoice.Id, eligibleMethodToActivate); + + if (newDetails is BitcoinLikeOnChainPaymentMethod bp) + { + var walletId = new WalletId(store.Id, paymentMethodId.CryptoCode); + if (bp.GetDepositAddress(((BTCPayNetwork)_btcPayNetworkProvider.GetNetwork(paymentMethodId.CryptoCode)).NBitcoinNetwork) is BitcoinAddress address) + { + await _walletRepository.EnsureWalletObjectLink( + new WalletObjectId( + walletId, + WalletObjectData.Types.Script, + address.ScriptPubKey.ToHex()), + new WalletObjectId( + walletId, + WalletObjectData.Types.Invoice, + invoice.Id)); + } + } + + _eventAggregator.Publish(new InvoicePaymentMethodActivated(paymentMethodId, invoice)); + _eventAggregator.Publish(new InvoiceNeedUpdateEvent(invoice.Id)); + success = true; + } + catch (PaymentMethodUnavailableException ex) + { + logs.Write($"{paymentMethodId}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error); + } + catch (Exception ex) + { + logs.Write($"{paymentMethodId}: Unexpected exception ({ex})", InvoiceEventData.EventSeverity.Error); + } + + await _invoiceRepository.AddInvoiceLogs(invoice.Id, logs); + } + return success; + } + } +} diff --git a/BTCPayServer/Services/Invoices/InvoiceExtensions.cs b/BTCPayServer/Services/Invoices/InvoiceExtensions.cs deleted file mode 100644 index 81faed426..000000000 --- a/BTCPayServer/Services/Invoices/InvoiceExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using BTCPayServer.Data; -using BTCPayServer.Events; -using BTCPayServer.Logging; -using BTCPayServer.Payments; - -namespace BTCPayServer.Services.Invoices -{ - public static class InvoiceExtensions - { - - public static async Task ActivateInvoicePaymentMethod(this InvoiceRepository invoiceRepository, - EventAggregator eventAggregator, BTCPayNetworkProvider btcPayNetworkProvider, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, - StoreData store, InvoiceEntity invoice, PaymentMethodId paymentMethodId) - { - if (invoice.GetInvoiceState().Status != InvoiceStatusLegacy.New) - return false; - bool success = false; - var eligibleMethodToActivate = invoice.GetPaymentMethod(paymentMethodId); - if (!eligibleMethodToActivate.GetPaymentMethodDetails().Activated) - { - var payHandler = paymentMethodHandlerDictionary[paymentMethodId]; - var supportPayMethod = invoice.GetSupportedPaymentMethod() - .Single(method => method.PaymentId == paymentMethodId); - var paymentMethod = invoice.GetPaymentMethod(paymentMethodId); - var network = btcPayNetworkProvider.GetNetwork(paymentMethodId.CryptoCode); - var prepare = payHandler.PreparePayment(supportPayMethod, store, network); - InvoiceLogs logs = new InvoiceLogs(); - try - { - var pmis = invoice.GetPaymentMethods().Select(method => method.GetId()).ToHashSet(); - logs.Write($"{paymentMethodId}: Activating", InvoiceEventData.EventSeverity.Info); - var newDetails = await - payHandler.CreatePaymentMethodDetails(logs, supportPayMethod, paymentMethod, store, network, - prepare, pmis); - eligibleMethodToActivate.SetPaymentMethodDetails(newDetails); - await invoiceRepository.UpdateInvoicePaymentMethod(invoice.Id, eligibleMethodToActivate); - eventAggregator.Publish(new InvoicePaymentMethodActivated(paymentMethodId, invoice)); - eventAggregator.Publish(new InvoiceNeedUpdateEvent(invoice.Id)); - success = true; - } - catch (PaymentMethodUnavailableException ex) - { - logs.Write($"{paymentMethodId}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error); - } - catch (Exception ex) - { - logs.Write($"{paymentMethodId}: Unexpected exception ({ex})", InvoiceEventData.EventSeverity.Error); - } - - await invoiceRepository.AddInvoiceLogs(invoice.Id, logs); - } - return success; - } - } -} diff --git a/BTCPayServer/Services/Wallets/BTCPayWallet.cs b/BTCPayServer/Services/Wallets/BTCPayWallet.cs index 3edd3a44e..7e9a67028 100644 --- a/BTCPayServer/Services/Wallets/BTCPayWallet.cs +++ b/BTCPayServer/Services/Wallets/BTCPayWallet.cs @@ -14,6 +14,7 @@ using NBitcoin; using NBXplorer; using NBXplorer.DerivationStrategy; using NBXplorer.Models; +using Newtonsoft.Json.Linq; namespace BTCPayServer.Services.Wallets { @@ -40,12 +41,14 @@ namespace BTCPayServer.Services.Wallets } public class BTCPayWallet { + public WalletRepository WalletRepository { get; } public NBXplorerConnectionFactory NbxplorerConnectionFactory { get; } public Logs Logs { get; } private readonly ExplorerClient _Client; private readonly IMemoryCache _MemoryCache; public BTCPayWallet(ExplorerClient client, IMemoryCache memoryCache, BTCPayNetwork network, + WalletRepository walletRepository, ApplicationDbContextFactory dbContextFactory, NBXplorerConnectionFactory nbxplorerConnectionFactory, Logs logs) { ArgumentNullException.ThrowIfNull(client); @@ -53,6 +56,7 @@ namespace BTCPayServer.Services.Wallets Logs = logs; _Client = client; _Network = network; + WalletRepository = walletRepository; _dbContextFactory = dbContextFactory; NbxplorerConnectionFactory = nbxplorerConnectionFactory; _MemoryCache = memoryCache; @@ -72,8 +76,10 @@ namespace BTCPayServer.Services.Wallets public TimeSpan CacheSpan { get; private set; } = TimeSpan.FromMinutes(5); - public async Task ReserveAddressAsync(DerivationStrategyBase derivationStrategy) + public async Task ReserveAddressAsync(string storeId, DerivationStrategyBase derivationStrategy, string generatedBy) { + if (storeId != null) + ArgumentNullException.ThrowIfNull(generatedBy); ArgumentNullException.ThrowIfNull(derivationStrategy); var pathInfo = await _Client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit, 0, true).ConfigureAwait(false); // Might happen on some broken install @@ -82,6 +88,12 @@ namespace BTCPayServer.Services.Wallets await _Client.TrackAsync(derivationStrategy).ConfigureAwait(false); pathInfo = await _Client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit, 0, true).ConfigureAwait(false); } + if (storeId != null) + { + await WalletRepository.EnsureWalletObject( + new WalletObjectId(new WalletId(storeId, Network.CryptoCode), WalletObjectData.Types.Script, pathInfo.ScriptPubKey.ToHex()), + new JObject() { ["generatedBy"] = generatedBy }); + } return pathInfo; } diff --git a/BTCPayServer/Services/Wallets/BTCPayWalletProvider.cs b/BTCPayServer/Services/Wallets/BTCPayWalletProvider.cs index 8e03e0bf8..b8baa19d1 100644 --- a/BTCPayServer/Services/Wallets/BTCPayWalletProvider.cs +++ b/BTCPayServer/Services/Wallets/BTCPayWalletProvider.cs @@ -9,6 +9,7 @@ namespace BTCPayServer.Services.Wallets { public class BTCPayWalletProvider { + public WalletRepository WalletRepository { get; } public Logs Logs { get; } private readonly ExplorerClientProvider _Client; @@ -19,12 +20,14 @@ namespace BTCPayServer.Services.Wallets Data.ApplicationDbContextFactory dbContextFactory, BTCPayNetworkProvider networkProvider, NBXplorerConnectionFactory nbxplorerConnectionFactory, + WalletRepository walletRepository, Logs logs) { ArgumentNullException.ThrowIfNull(client); this.Logs = logs; _Client = client; _NetworkProvider = networkProvider; + WalletRepository = walletRepository; _Options = memoryCacheOption; foreach (var network in networkProvider.GetAll().OfType()) @@ -32,7 +35,7 @@ namespace BTCPayServer.Services.Wallets var explorerClient = _Client.GetExplorerClient(network.CryptoCode); if (explorerClient == null) continue; - _Wallets.Add(network.CryptoCode.ToUpperInvariant(), new BTCPayWallet(explorerClient, new MemoryCache(_Options), network, dbContextFactory, nbxplorerConnectionFactory, Logs)); + _Wallets.Add(network.CryptoCode.ToUpperInvariant(), new BTCPayWallet(explorerClient, new MemoryCache(_Options), network, WalletRepository, dbContextFactory, nbxplorerConnectionFactory, Logs)); } } diff --git a/BTCPayServer/Services/Wallets/WalletReceiveService.cs b/BTCPayServer/Services/Wallets/WalletReceiveService.cs index cdc7f29c3..5fc075501 100644 --- a/BTCPayServer/Services/Wallets/WalletReceiveService.cs +++ b/BTCPayServer/Services/Wallets/WalletReceiveService.cs @@ -12,6 +12,7 @@ using NBitcoin; using NBXplorer; using NBXplorer.DerivationStrategy; using NBXplorer.Models; +using Newtonsoft.Json.Linq; namespace BTCPayServer.Services.Wallets { @@ -75,9 +76,7 @@ namespace BTCPayServer.Services.Wallets return null; } - var reserve = (await wallet.ReserveAddressAsync(derivationScheme.AccountDerivation)); - await _walletRepository.AddWalletTransactionAttachment(walletId, reserve.ScriptPubKey.ToHex(), new []{new Attachment("receive")}, - WalletObjectData.Types.Script); + var reserve = (await wallet.ReserveAddressAsync(walletId.StoreId, derivationScheme.AccountDerivation, "receive")); Set(walletId, reserve); return reserve; }