mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 14:04:26 +01:00
Merge pull request #2575 from NicolasDorier/refactor/wallet-cleanup
Cleanup some old code in wallet setup
This commit is contained in:
@@ -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<BTCPayNetwork>("BTC"));
|
||||
var parsed =
|
||||
|
||||
@@ -179,30 +179,18 @@ namespace BTCPayServer.Tests
|
||||
if (StoreId is null)
|
||||
await CreateStoreAsync();
|
||||
SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId);
|
||||
GenerateWalletResponseV = await parent.ExplorerClient.GenerateWalletAsync(new GenerateWalletRequest()
|
||||
var store = parent.PayTester.GetController<StoresController>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<IActionResult> 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<IActionResult> 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)
|
||||
|
||||
@@ -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> lightningNetworkOptions)
|
||||
IOptions<LightningNetworkOptions> 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")]
|
||||
|
||||
@@ -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<string>(GetDerivationSchemeSettings(walletId).AccountDerivation,
|
||||
WellknownMetadataKeys.MasterHDKey))
|
||||
};
|
||||
|
||||
@@ -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<string> hintedLabels = new HashSet<string>();
|
||||
|
||||
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<string> 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)
|
||||
{
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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<DerivationSchemeSettings>())
|
||||
{
|
||||
paymentMethod.IsHotWallet = paymentMethod.Source == "NBXplorer";
|
||||
paymentMethod.Source = "NBXplorerGenerated";
|
||||
}
|
||||
}
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task MigrateU2FToFIDO2()
|
||||
{
|
||||
await using var ctx = _DBContextFactory.CreateContext();
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
<input asp-for="Config" type="hidden"/>
|
||||
<input asp-for="Confirmation" type="hidden"/>
|
||||
<input asp-for="DerivationScheme" type="hidden"/>
|
||||
<input asp-for="Enabled" type="hidden"/>
|
||||
|
||||
<div class="form-group">
|
||||
<table class="table table-sm table-responsive-md">
|
||||
@@ -83,21 +82,6 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-4">
|
||||
<button class="btn btn-link" type="button" data-bs-toggle="collapse" data-bs-target="#wrong-addresses" aria-expanded="false" aria-controls="wrong-addresses">
|
||||
Wrong addresses?
|
||||
</button>
|
||||
<div id="wrong-addresses" class="collapse @(ViewContext.ModelState.IsValid ? "" : "show")">
|
||||
<div class="pb-1">
|
||||
<div class="form-group">
|
||||
<label asp-for="HintAddress" class="form-label">Help us to find the correct settings by telling us the first address of your wallet.</label>
|
||||
<input asp-for="HintAddress" class="form-control"/>
|
||||
<span asp-validation-for="HintAddress" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<button name="command" type="submit" class="btn btn-primary" value="save" id="Confirm">Confirm</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user