diff --git a/BTCPayServer/Controllers/StoresController.BTCLike.cs b/BTCPayServer/Controllers/StoresController.BTCLike.cs index cf4e6c92b..23082fb37 100644 --- a/BTCPayServer/Controllers/StoresController.BTCLike.cs +++ b/BTCPayServer/Controllers/StoresController.BTCLike.cs @@ -337,8 +337,10 @@ namespace BTCPayServer.Controllers for (int i = 0; i < 10; i++) { + var keyPath = deposit.GetKeyPath((uint)i); + var rootedKeyPath = vm.GetAccountKeypath()?.Derive(keyPath); var address = line.Derive((uint)i); - vm.AddressSamples.Add((deposit.GetKeyPath((uint)i).ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString())); + vm.AddressSamples.Add((keyPath.ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString(), rootedKeyPath)); } } vm.Confirmation = true; diff --git a/BTCPayServer/Controllers/VaultController.cs b/BTCPayServer/Controllers/VaultController.cs index f2aa24328..27821464f 100644 --- a/BTCPayServer/Controllers/VaultController.cs +++ b/BTCPayServer/Controllers/VaultController.cs @@ -168,6 +168,15 @@ namespace BTCPayServer.Controllers o.Add("psbt", psbt.ToBase64()); await websocketHelper.Send(o.ToString(), cancellationToken); break; + case "display-address": + if (await RequireDeviceUnlocking()) + { + continue; + } + var k = RootedKeyPath.Parse(await websocketHelper.NextMessageAsync(cancellationToken)); + await device.DisplayAddressAsync(GetScriptPubKeyType(k), k.KeyPath, cancellationToken); + await websocketHelper.Send("{ \"info\": \"ok\"}", cancellationToken); + break; case "ask-pin": if (device == null) { @@ -324,6 +333,18 @@ askdevice: return new EmptyResult(); } + private ScriptPubKeyType GetScriptPubKeyType(RootedKeyPath keyPath) + { + var path = keyPath.KeyPath.ToString(); + if (path.StartsWith("84'", StringComparison.OrdinalIgnoreCase)) + return ScriptPubKeyType.Segwit; + if (path.StartsWith("49'", StringComparison.OrdinalIgnoreCase)) + return ScriptPubKeyType.SegwitP2SH; + if (path.StartsWith("44'", StringComparison.OrdinalIgnoreCase)) + return ScriptPubKeyType.Legacy; + throw new NotSupportedException("Unsupported keypath"); + } + private bool SameSelector(DeviceSelector a, DeviceSelector b) { var aargs = new List(); diff --git a/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs b/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs index 1768eb151..474d03dd6 100644 --- a/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/DerivationSchemeViewModel.cs @@ -19,10 +19,10 @@ namespace BTCPayServer.Models.StoreViewModels get; set; } - public List<(string KeyPath, string Address)> AddressSamples + public List<(string KeyPath, string Address, RootedKeyPath RootedKeyPath)> AddressSamples { get; set; - } = new List<(string KeyPath, string Address)>(); + } = new List<(string KeyPath, string Address, RootedKeyPath RootedKeyPath)>(); public string CryptoCode { get; set; } public string KeyPath { get; set; } @@ -41,5 +41,16 @@ namespace BTCPayServer.Models.StoreViewModels public string DerivationSchemeFormat { get; set; } public string AccountKey { get; set; } public BTCPayNetwork Network { get; set; } + + public RootedKeyPath GetAccountKeypath() + { + if (KeyPath != null && RootFingerprint != null && + NBitcoin.KeyPath.TryParse(KeyPath, out var p) && + HDFingerprint.TryParse(RootFingerprint, out var fp)) + { + return new RootedKeyPath(fp, p); + } + return null; + } } } diff --git a/BTCPayServer/Views/Stores/AddDerivationScheme.cshtml b/BTCPayServer/Views/Stores/AddDerivationScheme.cshtml index e62478de9..24b32dd3e 100644 --- a/BTCPayServer/Views/Stores/AddDerivationScheme.cshtml +++ b/BTCPayServer/Views/Stores/AddDerivationScheme.cshtml @@ -6,6 +6,7 @@ @section HeadScripts {