diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 9136a2589..a58ee4c02 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -47,7 +47,7 @@ all runtime; build; native; contentfiles; analyzers - + diff --git a/BTCPayServer/Services/LedgerHardwareWalletService.cs b/BTCPayServer/Services/LedgerHardwareWalletService.cs index ce6de932f..798509b5d 100644 --- a/BTCPayServer/Services/LedgerHardwareWalletService.cs +++ b/BTCPayServer/Services/LedgerHardwareWalletService.cs @@ -114,11 +114,7 @@ namespace BTCPayServer.Services account.Indexes.Length == 0 ? 0 : account.Indexes.Last()).GetWif(network.NBitcoinNetwork); return extpubkey; } - class HDKey - { - public PubKey PubKey { get; set; } - public KeyPath KeyPath { get; set; } - } + public override async Task SignTransactionAsync(PSBT psbt, HDFingerprint? rootFingerprint, BitcoinExtPubKey accountKey, Script changeHint, CancellationToken cancellationToken) { HashSet knownFingerprints = new HashSet(); @@ -126,22 +122,20 @@ namespace BTCPayServer.Services if (rootFingerprint is HDFingerprint fp) knownFingerprints.Add(fp); var unsigned = psbt.GetGlobalTransaction(); - var changeKeyPath = psbt.Outputs - .Where(o => changeHint == null ? true : changeHint == o.ScriptPubKey) - .Select(o => (Output: o, HDKey: GetHDKey(knownFingerprints, accountKey, o))) - .Where(o => o.HDKey != null) - .Select(o => o.HDKey.KeyPath) + var changeKeyPath = psbt.Outputs.HDKeysFor(rootFingerprint, accountKey) + .Where(o => changeHint == null ? true : changeHint == o.Coin.ScriptPubKey) + .Select(o => o.KeyPath) .FirstOrDefault(); var signatureRequests = psbt .Inputs - .Select(i => (Input: i, HDKey: GetHDKey(knownFingerprints, accountKey, i))) - .Where(i => i.HDKey != null) + .HDKeysFor(rootFingerprint, accountKey) + .GroupBy(hd => hd.Coin) .Select(i => new SignatureRequest() { - InputCoin = i.Input.GetSignableCoin(), - InputTransaction = i.Input.NonWitnessUtxo, - KeyPath = i.HDKey.KeyPath, - PubKey = i.HDKey.PubKey + InputCoin = i.Key.GetSignableCoin(), + InputTransaction = i.Key.NonWitnessUtxo, + KeyPath = i.First().KeyPath, + PubKey = i.First().PubKey }).ToArray(); var signedTransaction = await Ledger.SignTransactionAsync(signatureRequests, unsigned, changeKeyPath, cancellationToken); if (signedTransaction == null) @@ -160,22 +154,6 @@ namespace BTCPayServer.Services return psbt; } - private HDKey GetHDKey(HashSet knownFingerprints, BitcoinExtPubKey accountKey, PSBTCoin coin) - { - // Check if the accountKey match this coin by checking if the non hardened last part of the path - // can derive the same pubkey - foreach (var key in coin.HDKeyPaths) - { - if (!knownFingerprints.Contains(key.Value.Item1)) - continue; - var accountKeyPath = key.Value.Item2.GetAccountKeyPath(); - // We might have a fingerprint collision, let's check - if (accountKey.ExtPubKey.Derive(accountKeyPath).GetPublicKey() == key.Key) - return new HDKey() { KeyPath = key.Value.Item2, PubKey = key.Key }; - } - return null; - } - public override void Dispose() { if (_Transport != null)