diff --git a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs index 8ec19f555..da38b633f 100644 --- a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs +++ b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs @@ -954,28 +954,6 @@ normal: result = testnetParser.Parse(tpub); Assert.Equal(tpub, result.ToString()); - testnetParser.HintScriptPubKey = BitcoinAddress - .Create("tb1q4s33amqm8l7a07zdxcunqnn3gcsjcfz3xc573l", testnetParser.Network).ScriptPubKey; - result = testnetParser.Parse(tpub); - Assert.Equal(tpub, result.ToString()); - - testnetParser.HintScriptPubKey = BitcoinAddress - .Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey; - result = testnetParser.Parse(tpub); - Assert.Equal($"{tpub}-[p2sh]", result.ToString()); - - testnetParser.HintScriptPubKey = BitcoinAddress - .Create("mwD8bHS65cdgUf6rZUUSoVhi3wNQFu1Nfi", testnetParser.Network).ScriptPubKey; - result = testnetParser.Parse(tpub); - Assert.Equal($"{tpub}-[legacy]", result.ToString()); - - testnetParser.HintScriptPubKey = BitcoinAddress - .Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey; - result = testnetParser.Parse($"{tpub}-[legacy]"); - Assert.Equal($"{tpub}-[p2sh]", result.ToString()); - - result = testnetParser.Parse(tpub); - Assert.Equal($"{tpub}-[p2sh]", result.ToString()); var regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork("BTC")); var parsed = diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 66771847d..095919234 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -179,30 +179,18 @@ namespace BTCPayServer.Tests if (StoreId is null) await CreateStoreAsync(); SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode); - var store = parent.PayTester.GetController(UserId, StoreId); - GenerateWalletResponseV = await parent.ExplorerClient.GenerateWalletAsync(new GenerateWalletRequest() + var store = parent.PayTester.GetController(UserId, StoreId, true); + + var generateRequest = new GenerateWalletRequest() { ScriptPubKeyType = segwit, SavePrivateKeys = importKeysToNBX, ImportKeysToRPC = importsKeysToBitcoinCore - }); - await store.UpdateWallet( - new WalletSetupViewModel - { - StoreId = StoreId, - Method = importKeysToNBX ? WalletSetupMethod.HotWallet : WalletSetupMethod.WatchOnly, - Enabled = true, - CryptoCode = cryptoCode, - Network = SupportedNetwork, - RootFingerprint = GenerateWalletResponseV.AccountKeyPath.MasterFingerprint.ToString(), - RootKeyPath = SupportedNetwork.GetRootKeyPath(), - Source = "NBXplorer", - AccountKey = GenerateWalletResponseV.AccountHDKey.Neuter().ToWif(), - DerivationSchemeFormat = "BTCPay", - KeyPath = GenerateWalletResponseV.AccountKeyPath.KeyPath.ToString(), - DerivationScheme = DerivationScheme.ToString(), - Confirmation = true - }); + }; + + await store.GenerateWallet(StoreId, cryptoCode, WalletSetupMethod.HotWallet, generateRequest); + Assert.NotNull(store.GenerateWalletResponse); + GenerateWalletResponseV = store.GenerateWalletResponse; return new WalletId(StoreId, cryptoCode); } diff --git a/BTCPayServer/Controllers/StoresController.Onchain.cs b/BTCPayServer/Controllers/StoresController.Onchain.cs index f28834407..23d233820 100644 --- a/BTCPayServer/Controllers/StoresController.Onchain.cs +++ b/BTCPayServer/Controllers/StoresController.Onchain.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; @@ -11,9 +12,11 @@ using BTCPayServer.Models; using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Payments; using BTCPayServer.Services; +using ExchangeSharp; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using NBitcoin; using NBXplorer; using NBXplorer.DerivationStrategy; @@ -85,15 +88,6 @@ namespace BTCPayServer.Controllers return NotFound(); } - if (!string.IsNullOrEmpty(vm.Config)) - { - if (!DerivationSchemeSettings.TryParseFromJson(vm.Config, network, out strategy)) - { - ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format"); - return View(vm.ViewName, vm); - } - } - if (vm.WalletFile != null) { if (!DerivationSchemeSettings.TryParseFromWalletFile(await ReadAllText(vm.WalletFile), network, out strategy)) @@ -114,31 +108,25 @@ namespace BTCPayServer.Controllers { try { - var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, null, network); - if (newStrategy.AccountDerivation != strategy?.AccountDerivation) + strategy = ParseDerivationStrategy(vm.DerivationScheme, network); + strategy.Source = "ManualDerivationScheme"; + if (!string.IsNullOrEmpty(vm.AccountKey)) { - var accountKey = string.IsNullOrEmpty(vm.AccountKey) - ? null - : new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); - if (accountKey != null) + var accountKey = new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); + var accountSettings = + strategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); + if (accountSettings != null) { - var accountSettings = - newStrategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); - if (accountSettings != null) - { - accountSettings.AccountKeyPath = - vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); - accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) - ? (HDFingerprint?)null - : new HDFingerprint( - NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); - } + accountSettings.AccountKeyPath = + vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); + accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) + ? (HDFingerprint?)null + : new HDFingerprint( + NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); } - - strategy = newStrategy; - strategy.Source = vm.Source; - vm.DerivationScheme = strategy.AccountDerivation.ToString(); } + vm.DerivationScheme = strategy.AccountDerivation.ToString(); + ModelState.Remove(nameof(vm.DerivationScheme)); } catch { @@ -146,34 +134,33 @@ namespace BTCPayServer.Controllers return View(vm.ViewName, vm); } } - else + else if (!string.IsNullOrEmpty(vm.Config)) + { + if (!DerivationSchemeSettings.TryParseFromJson(UnprotectString(vm.Config), network, out strategy)) + { + ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format"); + return View(vm.ViewName, vm); + } + } + + if (strategy is null) { ModelState.AddModelError(nameof(vm.DerivationScheme), "Please provide your extended public key"); return View(vm.ViewName, vm); } - var oldConfig = vm.Config; - vm.Config = strategy?.ToJson(); - var configChanged = oldConfig != vm.Config; + vm.Config = ProtectString(strategy.ToJson()); + ModelState.Remove(nameof(vm.Config)); + PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); var storeBlob = store.GetStoreBlob(); - var willBeExcluded = !vm.Enabled; - - var showAddress = // Show addresses if: - // - If the user is testing the hint address in confirmation screen - (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) || - // - The user is clicking on continue after changing the config - (!vm.Confirmation && configChanged); - - showAddress = showAddress && strategy != null; - if (!showAddress) + if (vm.Confirmation) { try { - if (strategy != null) - await wallet.TrackAsync(strategy.AccountDerivation); + await wallet.TrackAsync(strategy.AccountDerivation); store.SetSupportedPaymentMethod(paymentMethodId, strategy); - storeBlob.SetExcluded(paymentMethodId, willBeExcluded); + storeBlob.SetExcluded(paymentMethodId, false); storeBlob.Hints.Wallet = false; store.SetStoreBlob(storeBlob); } @@ -184,52 +171,25 @@ namespace BTCPayServer.Controllers } await _Repo.UpdateStore(store); - _EventAggregator.Publish(new WalletChangedEvent {WalletId = new WalletId(vm.StoreId, vm.CryptoCode)}); + _EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(vm.StoreId, vm.CryptoCode) }); TempData[WellKnownTempData.SuccessMessage] = $"Wallet settings for {network.CryptoCode} have been updated."; // This is success case when derivation scheme is added to the store - return RedirectToAction(nameof(UpdateStore), new {storeId = vm.StoreId}); + return RedirectToAction(nameof(UpdateStore), new { storeId = vm.StoreId }); } - - if (!string.IsNullOrEmpty(vm.HintAddress)) - { - BitcoinAddress address; - try - { - address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork); - } - catch - { - ModelState.AddModelError(nameof(vm.HintAddress), "Invalid hint address"); - return ConfirmAddresses(vm, strategy); - } - - try - { - var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network); - if (newStrategy.AccountDerivation != strategy.AccountDerivation) - { - strategy.AccountDerivation = newStrategy.AccountDerivation; - strategy.AccountOriginal = null; - } - } - catch - { - ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address. Are you sure the wallet and address provided are correct and from the same source?"); - return ConfirmAddresses(vm, strategy); - } - - vm.HintAddress = ""; - TempData[WellKnownTempData.SuccessMessage] = - "Address successfully found, please verify that the rest is correct and click on \"Confirm\""; - ModelState.Remove(nameof(vm.HintAddress)); - ModelState.Remove(nameof(vm.DerivationScheme)); - } - return ConfirmAddresses(vm, strategy); } + private string ProtectString(string str) + { + return Convert.ToBase64String(DataProtector.Protect(Encoding.UTF8.GetBytes(str))); + } + private string UnprotectString(string str) + { + return Encoding.UTF8.GetString(DataProtector.Unprotect(Convert.FromBase64String(str))); + } + [HttpGet("{storeId}/onchain/{cryptoCode}/generate/{method?}")] public async Task GenerateWallet(WalletSetupViewModel vm) { @@ -246,14 +206,6 @@ namespace BTCPayServer.Controllers return NotFound(); } - var derivation = GetExistingDerivationStrategy(vm.CryptoCode, store); - if (derivation != null) - { - vm.DerivationScheme = derivation.AccountDerivation.ToString(); - vm.Config = derivation.ToJson(); - } - - vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike)); vm.CanUseHotWallet = hotWallet; vm.CanUseRPCImport = rpcImport; vm.RootKeyPath = network.GetRootKeyPath(); @@ -270,7 +222,7 @@ namespace BTCPayServer.Controllers return View(vm.ViewName, vm); } - + internal GenerateWalletResponse GenerateWalletResponse; [HttpPost("{storeId}/onchain/{cryptoCode}/generate/{method}")] public async Task GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, GenerateWalletRequest request) { @@ -288,6 +240,7 @@ namespace BTCPayServer.Controllers var client = _ExplorerProvider.GetExplorerClient(cryptoCode); var isImport = method == WalletSetupMethod.Seed; + var vm = new WalletSetupViewModel { StoreId = storeId, @@ -297,8 +250,8 @@ namespace BTCPayServer.Controllers Confirmation = string.IsNullOrEmpty(request.ExistingMnemonic), Network = network, RootKeyPath = network.GetRootKeyPath(), - Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike)), - Source = "NBXplorer", + Source = isImport ? "SeedImported" : "NBXplorerGenerated", + IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet, DerivationSchemeFormat = "BTCPay", CanUseHotWallet = true, CanUseRPCImport = rpcImport @@ -329,11 +282,26 @@ namespace BTCPayServer.Controllers return View(vm.ViewName, vm); } + var derivationSchemeSettings = new DerivationSchemeSettings(response.DerivationScheme, network); + if (method == WalletSetupMethod.Seed) + { + derivationSchemeSettings.Source = "ImportedSeed"; + derivationSchemeSettings.IsHotWallet = request.SavePrivateKeys; + } + else + { + derivationSchemeSettings.Source = "NBXplorerGenerated"; + derivationSchemeSettings.IsHotWallet = method == WalletSetupMethod.HotWallet; + } + + var accountSettings = derivationSchemeSettings.GetSigningAccountKeySettings(); + accountSettings.AccountKeyPath = response.AccountKeyPath.KeyPath; + accountSettings.RootFingerprint = response.AccountKeyPath.MasterFingerprint; + derivationSchemeSettings.AccountOriginal = response.DerivationScheme.ToString(); + // Set wallet properties from generate response - vm.RootFingerprint = response.AccountKeyPath.MasterFingerprint.ToString(); - vm.DerivationScheme = response.DerivationScheme.ToString(); - vm.AccountKey = response.AccountHDKey.Neuter().ToWif(); - vm.KeyPath = response.AccountKeyPath.KeyPath.ToString(); + vm.Config = ProtectString(derivationSchemeSettings.ToJson()); + var result = await UpdateWallet(vm); @@ -353,8 +321,12 @@ namespace BTCPayServer.Controllers Mnemonic = response.Mnemonic, Passphrase = response.Passphrase, IsStored = request.SavePrivateKeys, - ReturnUrl = Url.Action(nameof(GenerateWalletConfirm), new {storeId, cryptoCode}) + ReturnUrl = Url.Action(nameof(GenerateWalletConfirm), new { storeId, cryptoCode }) }; + if (this._BTCPayEnv.IsDeveloping) + { + GenerateWalletResponse = response; + } return this.RedirectToRecoverySeedBackup(seedVm); } @@ -379,7 +351,7 @@ namespace BTCPayServer.Controllers TempData[WellKnownTempData.SuccessMessage] = $"Wallet settings for {network.CryptoCode} have been updated."; - return RedirectToAction(nameof(UpdateStore), new {storeId}); + return RedirectToAction(nameof(UpdateStore), new { storeId }); } [HttpGet("{storeId}/onchain/{cryptoCode}/modify")] @@ -408,8 +380,7 @@ namespace BTCPayServer.Controllers vm.RootFingerprint = derivation.GetSigningAccountKeySettings().RootFingerprint.ToString(); vm.DerivationScheme = derivation.AccountDerivation.ToString(); vm.KeyPath = derivation.GetSigningAccountKeySettings().AccountKeyPath?.ToString(); - vm.Config = derivation.ToJson(); - vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike)); + vm.Config = ProtectString(derivation.ToJson()); vm.IsHotWallet = isHotWallet; return View(vm); @@ -460,7 +431,7 @@ namespace BTCPayServer.Controllers return NotFound(); } - return RedirectToAction(nameof(SetupWallet), new {storeId, cryptoCode}); + return RedirectToAction(nameof(SetupWallet), new { storeId, cryptoCode }); } [HttpGet("{storeId}/onchain/{cryptoCode}/delete")] @@ -519,12 +490,12 @@ namespace BTCPayServer.Controllers storeBlob.SetExcluded(paymentMethodId, !enabled); store.SetStoreBlob(storeBlob); await _Repo.UpdateStore(store); - _EventAggregator.Publish(new WalletChangedEvent {WalletId = new WalletId(storeId, cryptoCode)}); + _EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(storeId, cryptoCode) }); TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} on-chain payments are now {(enabled ? "enabled" : "disabled")} for this store."; - return RedirectToAction(nameof(UpdateStore), new {storeId}); + return RedirectToAction(nameof(UpdateStore), new { storeId }); } [HttpPost("{storeId}/onchain/{cryptoCode}/delete")] @@ -546,12 +517,12 @@ namespace BTCPayServer.Controllers store.SetSupportedPaymentMethod(paymentMethodId, null); await _Repo.UpdateStore(store); - _EventAggregator.Publish(new WalletChangedEvent {WalletId = new WalletId(storeId, cryptoCode)}); + _EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(storeId, cryptoCode) }); TempData[WellKnownTempData.SuccessMessage] = $"On-Chain payment for {network.CryptoCode} has been removed."; - return RedirectToAction(nameof(UpdateStore), new {storeId}); + return RedirectToAction(nameof(UpdateStore), new { storeId }); } private IActionResult ConfirmAddresses(WalletSetupViewModel vm, DerivationSchemeSettings strategy) diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index d95cfd37d..4076049c7 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -27,6 +27,7 @@ using BTCPayServer.Services.Stores; using BTCPayServer.Services.Wallets; using BundlerMinifier.TagHelpers; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -69,7 +70,8 @@ namespace BTCPayServer.Controllers AppService appService, IWebHostEnvironment webHostEnvironment, WebhookNotificationManager webhookNotificationManager, - IOptions lightningNetworkOptions) + IOptions lightningNetworkOptions, + IDataProtectionProvider dataProtector) { _RateFactory = rateFactory; _Repo = repo; @@ -85,6 +87,7 @@ namespace BTCPayServer.Controllers _appService = appService; _webHostEnvironment = webHostEnvironment; _lightningNetworkOptions = lightningNetworkOptions; + DataProtector = dataProtector.CreateProtector("ConfigProtector"); WebhookNotificationManager = webhookNotificationManager; _EventAggregator = eventAggregator; _NetworkProvider = networkProvider; @@ -689,10 +692,9 @@ namespace BTCPayServer.Controllers } - private DerivationSchemeSettings ParseDerivationStrategy(string derivationScheme, Script hint, BTCPayNetwork network) + private DerivationSchemeSettings ParseDerivationStrategy(string derivationScheme, BTCPayNetwork network) { var parser = new DerivationSchemeParser(network); - parser.HintScriptPubKey = hint; try { var derivationSchemeSettings = new DerivationSchemeSettings(); @@ -827,6 +829,7 @@ namespace BTCPayServer.Controllers public string GeneratedPairingCode { get; set; } public WebhookNotificationManager WebhookNotificationManager { get; } + public IDataProtector DataProtector { get; } [HttpGet] [Route("{storeId}/Tokens/Create")] diff --git a/BTCPayServer/Controllers/WalletsController.cs b/BTCPayServer/Controllers/WalletsController.cs index f950a97bc..6917a5ba1 100644 --- a/BTCPayServer/Controllers/WalletsController.cs +++ b/BTCPayServer/Controllers/WalletsController.cs @@ -1088,7 +1088,9 @@ namespace BTCPayServer.Controllers DerivationScheme = derivationSchemeSettings.AccountDerivation.ToString(), DerivationSchemeInput = derivationSchemeSettings.AccountOriginal, SelectedSigningKey = derivationSchemeSettings.SigningKey.ToString(), - NBXSeedAvailable = await CanUseHotWallet() && !string.IsNullOrEmpty(await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode) + NBXSeedAvailable = derivationSchemeSettings.IsHotWallet && + await CanUseHotWallet() && + !string.IsNullOrEmpty(await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode) .GetMetadataAsync(GetDerivationSchemeSettings(walletId).AccountDerivation, WellknownMetadataKeys.MasterHDKey)) }; diff --git a/BTCPayServer/DerivationSchemeParser.cs b/BTCPayServer/DerivationSchemeParser.cs index bd79c9634..7e8d9845f 100644 --- a/BTCPayServer/DerivationSchemeParser.cs +++ b/BTCPayServer/DerivationSchemeParser.cs @@ -13,8 +13,6 @@ namespace BTCPayServer public Network Network => BtcPayNetwork.NBitcoinNetwork; - public Script HintScriptPubKey { get; set; } - public DerivationSchemeParser(BTCPayNetwork expectedNetwork) { if (expectedNetwork == null) @@ -131,19 +129,6 @@ namespace BTCPayServer HashSet hintedLabels = new HashSet(); - var hintDestination = HintScriptPubKey?.GetDestination(); - if (hintDestination != null) - { - if (hintDestination is KeyId) - { - hintedLabels.Add("legacy"); - } - if (hintDestination is ScriptId) - { - hintedLabels.Add("p2sh"); - } - } - if (!Network.Consensus.SupportSegwit) { hintedLabels.Add("legacy"); @@ -152,8 +137,7 @@ namespace BTCPayServer try { - var result = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str); - return FindMatch(hintedLabels, result); + return BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str); } catch { @@ -205,22 +189,13 @@ namespace BTCPayServer catch { continue; } } - if (hintDestination != null) - { - if (hintDestination is WitKeyId) - { - hintedLabels.Remove("legacy"); - hintedLabels.Remove("p2sh"); - } - } - str = string.Join('-', parts.Where(p => !IsLabel(p))); foreach (var label in hintedLabels) { str = $"{str}-[{label}]"; } - return FindMatch(hintedLabels, BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str)); + return BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str); } public static BitcoinExtPubKey GetBitcoinExtPubKeyByNetwork(Network network, byte[] data) @@ -235,27 +210,6 @@ namespace BTCPayServer } } - private DerivationStrategyBase FindMatch(HashSet hintLabels, DerivationStrategyBase result) - { - var firstKeyPath = new KeyPath("0/0"); - if (HintScriptPubKey == null) - return result; - if (HintScriptPubKey == result.GetDerivation(firstKeyPath).ScriptPubKey) - return result; - - if (result is MultisigDerivationStrategy) - hintLabels.Add("keeporder"); - - var resultNoLabels = result.ToString(); - resultNoLabels = string.Join('-', resultNoLabels.Split('-').Where(p => !IsLabel(p))); - foreach (var labels in ItemCombinations(hintLabels.ToList())) - { - var hinted = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(resultNoLabels + '-' + string.Join('-', labels.Select(l => $"[{l}]").ToArray())); - if (HintScriptPubKey == hinted.GetDerivation(firstKeyPath).ScriptPubKey) - return hinted; - } - throw new FormatException("Could not find any match"); - } private static bool IsLabel(string v) { diff --git a/BTCPayServer/DerivationSchemeSettings.cs b/BTCPayServer/DerivationSchemeSettings.cs index ba496826f..8dad2ef22 100644 --- a/BTCPayServer/DerivationSchemeSettings.cs +++ b/BTCPayServer/DerivationSchemeSettings.cs @@ -276,8 +276,8 @@ namespace BTCPayServer [JsonIgnore] public BTCPayNetwork Network { get; set; } public string Source { get; set; } - [JsonIgnore] - public bool IsHotWallet => Source == "NBXplorer"; + + public bool IsHotWallet { get; set; } [Obsolete("Use GetSigningAccountKeySettings().AccountKeyPath instead")] [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] diff --git a/BTCPayServer/Hosting/MigrationStartupTask.cs b/BTCPayServer/Hosting/MigrationStartupTask.cs index 7294403bd..de84b6448 100644 --- a/BTCPayServer/Hosting/MigrationStartupTask.cs +++ b/BTCPayServer/Hosting/MigrationStartupTask.cs @@ -128,6 +128,12 @@ namespace BTCPayServer.Hosting settings.MigrateU2FToFIDO2 = true; await _Settings.UpdateSetting(settings); } + if (!settings.MigrateHotwalletProperty) + { + await MigrateHotwalletProperty(); + settings.MigrateHotwalletProperty = true; + await _Settings.UpdateSetting(settings); + } } catch (Exception ex) { @@ -136,6 +142,20 @@ namespace BTCPayServer.Hosting } } + private async Task MigrateHotwalletProperty() + { + await using var ctx = _DBContextFactory.CreateContext(); + foreach (var store in await ctx.Stores.AsQueryable().ToArrayAsync()) + { + foreach (var paymentMethod in store.GetSupportedPaymentMethods(_NetworkProvider).OfType()) + { + paymentMethod.IsHotWallet = paymentMethod.Source == "NBXplorer"; + paymentMethod.Source = "NBXplorerGenerated"; + } + } + await ctx.SaveChangesAsync(); + } + private async Task MigrateU2FToFIDO2() { await using var ctx = _DBContextFactory.CreateContext(); diff --git a/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs b/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs index a88b277ef..14d40d918 100644 --- a/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs @@ -20,10 +20,7 @@ namespace BTCPayServer.Models.StoreViewModels public string KeyPath { get; set; } [Display(Name = "Root fingerprint")] public string RootFingerprint { get; set; } - [Display(Name = "Hint address")] - public string HintAddress { get; set; } public bool Confirmation { get; set; } - public bool Enabled { get; set; } = true; public KeyPath RootKeyPath { get; set; } diff --git a/BTCPayServer/Services/MigrationSettings.cs b/BTCPayServer/Services/MigrationSettings.cs index 56d63ff68..c8bec9c30 100644 --- a/BTCPayServer/Services/MigrationSettings.cs +++ b/BTCPayServer/Services/MigrationSettings.cs @@ -2,6 +2,7 @@ namespace BTCPayServer.Services { public class MigrationSettings { + public bool MigrateHotwalletProperty { get; set; } public bool MigrateU2FToFIDO2{ get; set; } public bool UnreachableStoreCheck { get; set; } public bool DeprecatedLightningConnectionStringCheck { get; set; } diff --git a/BTCPayServer/Views/Stores/ImportWallet/ConfirmAddresses.cshtml b/BTCPayServer/Views/Stores/ImportWallet/ConfirmAddresses.cshtml index cbdc1a32d..11577a00c 100644 --- a/BTCPayServer/Views/Stores/ImportWallet/ConfirmAddresses.cshtml +++ b/BTCPayServer/Views/Stores/ImportWallet/ConfirmAddresses.cshtml @@ -50,7 +50,6 @@ -
@@ -83,21 +82,6 @@
-
- -
-
-
- - - -
-
-
-
-