Skip to content

Commit

Permalink
Merge pull request #67 from Elenpay/develop
Browse files Browse the repository at this point in the history
Fixed #65 (#66)
  • Loading branch information
Jossec101 authored Jan 13, 2023
2 parents a46f195 + ce8e747 commit 17e94d6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 37 deletions.
58 changes: 58 additions & 0 deletions src/Helpers/LightningHelper.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using AutoMapper;
using FundsManager.Data.Models;
using FundsManager.Services;
using Google.Protobuf;
using NBitcoin;
using NBXplorer;
using NBXplorer.Models;
using Key = FundsManager.Data.Models.Key;

namespace FundsManager.Helpers
{
Expand All @@ -18,6 +20,62 @@ public static void RemoveDuplicateUTXOs(this UTXOChanges utxoChanges)
utxoChanges.Confirmed.UTXOs = utxoChanges.Confirmed.UTXOs.DistinctBy(x => x.Outpoint).ToList();
utxoChanges.Unconfirmed.UTXOs = utxoChanges.Unconfirmed.UTXOs.DistinctBy(x => x.Outpoint).ToList();
}

/// <summary>
/// Helper that adds global xpubs fields and derivation paths in the PSBT inputs to allow hardware wallets or the remote signer to find the right key to sign
/// </summary>
/// <param name="logger"></param>
/// <param name="keys"></param>
/// <param name="result"></param>
/// <param name="selectedUtxOs"></param>
/// <param name="multisigCoins"></param>
/// <exception cref="ArgumentException"></exception>
public static void AddDerivationData(ILogger logger, IEnumerable<Key> keys , (PSBT?, bool) result, List<UTXO> selectedUtxOs,
List<ScriptCoin> multisigCoins)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (keys == null) throw new ArgumentNullException(nameof(keys));
if (selectedUtxOs == null) throw new ArgumentNullException(nameof(selectedUtxOs));
if (multisigCoins == null) throw new ArgumentNullException(nameof(multisigCoins));

var nbXplorerNetwork = CurrentNetworkHelper.GetCurrentNetwork();
foreach (var key in keys)
{
var bitcoinExtPubKey = new BitcoinExtPubKey(key.XPUB, nbXplorerNetwork);

var masterFingerprint = HDFingerprint.Parse(key.MasterFingerprint);
var rootedKeyPath = new RootedKeyPath(masterFingerprint, new KeyPath(key.Path));

//Global xpubs field addition
result.Item1.GlobalXPubs.Add(
bitcoinExtPubKey,
rootedKeyPath
);

foreach (var selectedUtxo in selectedUtxOs)
{
var utxoDerivationPath = KeyPath.Parse(key.Path).Derive(selectedUtxo.KeyPath);
var derivedPubKey = bitcoinExtPubKey.Derive(selectedUtxo.KeyPath).GetPublicKey();

var input = result.Item1.Inputs.FirstOrDefault(input =>
input?.GetCoin()?.Outpoint == selectedUtxo.Outpoint);
var addressRootedKeyPath = new RootedKeyPath(masterFingerprint, utxoDerivationPath);
var multisigCoin = multisigCoins.FirstOrDefault(x => x.Outpoint == selectedUtxo.Outpoint);

if (multisigCoin != null && input != null && multisigCoin.Redeem.GetAllPubKeys().Contains(derivedPubKey))
{
input.AddKeyPath(derivedPubKey, addressRootedKeyPath);
}
else
{
var errorMessage = $"Invalid derived pub key for utxo:{selectedUtxo.Outpoint}";
logger.LogError(errorMessage);
throw new ArgumentException(errorMessage, nameof(derivedPubKey));
}
}
}
}


/// <summary>
/// Generates the ExplorerClient for using nbxplorer based on a bitcoin networy type
Expand Down
3 changes: 3 additions & 0 deletions src/Services/BitcoinService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ public BitcoinService(ILogger<BitcoinService> logger,
}

result.Item1 = builder.BuildPSBT(false);

//Additional fields to support PSBT signing with a HW or the Remote Signer
LightningHelper.AddDerivationData(_logger,walletWithdrawalRequest.Wallet.Keys, result, selectedUTXOs, scriptCoins);
}
catch (Exception e)
{
Expand Down
42 changes: 5 additions & 37 deletions src/Services/LightningService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Microsoft.EntityFrameworkCore;
using AddressType = Lnrpc.AddressType;
using Channel = FundsManager.Data.Models.Channel;
using Key = FundsManager.Data.Models.Key;
using ListUnspentRequest = Lnrpc.ListUnspentRequest;
using Transaction = NBitcoin.Transaction;
using UTXO = NBXplorer.Models.UTXO;
Expand Down Expand Up @@ -822,47 +823,14 @@ private void CancelPendingChannel(Node source, Lightning.LightningClient client,

result.Item1 = builder.BuildPSBT(false);

//TODO Remove hack when https://github.com/MetacoSA/NBitcoin/issues/1112 is fixed
//Hack, see https://github.com/MetacoSA/NBitcoin/issues/1112 for details
foreach (var input in result.Item1.Inputs)
{
input.SighashType = SigHash.None;
}

//Additional fields to support PSBT signing with a HW
foreach (var key in channelOperationRequest.Wallet.Keys)
{
var bitcoinExtPubKey = new BitcoinExtPubKey(key.XPUB, nbXplorerNetwork);

var masterFingerprint = HDFingerprint.Parse(key.MasterFingerprint);
var rootedKeyPath = new RootedKeyPath(masterFingerprint, new KeyPath(key.Path));

//Global xpubs field addition
result.Item1.GlobalXPubs.Add(
bitcoinExtPubKey,
rootedKeyPath
);

foreach (var selectedUtxo in selectedUtxOs)
{
var utxoDerivationPath = KeyPath.Parse(key.Path).Derive(selectedUtxo.KeyPath);
var derivedPubKey = bitcoinExtPubKey.Derive(selectedUtxo.KeyPath).GetPublicKey();

var input = result.Item1.Inputs.FirstOrDefault(input => input?.GetCoin()?.Outpoint == selectedUtxo.Outpoint);
var addressRootedKeyPath = new RootedKeyPath(masterFingerprint, utxoDerivationPath);
var multisigCoin = multisigCoins.FirstOrDefault(x => x.Outpoint == selectedUtxo.Outpoint);

if (multisigCoin != null && input != null && multisigCoin.Redeem.GetAllPubKeys().Contains(derivedPubKey))
{
input.AddKeyPath(derivedPubKey, addressRootedKeyPath);
}
else
{
var errorMessage = $"Invalid derived pub key for utxo:{selectedUtxo.Outpoint}";
_logger.LogError(errorMessage);
throw new ArgumentException(errorMessage, nameof(derivedPubKey));
}
}
}
//Additional fields to support PSBT signing with a HW or the Remote Signer
LightningHelper.AddDerivationData(_logger,channelOperationRequest.Wallet.Keys, result, selectedUtxOs, multisigCoins);
}
catch (Exception e)
{
Expand All @@ -880,7 +848,6 @@ private void CancelPendingChannel(Node source, Lightning.LightningClient client,
}

// The template PSBT is saved for later reuse

if (result.Item1 != null)
{
var psbt = new ChannelOperationRequestPSBT
Expand All @@ -903,6 +870,7 @@ private void CancelPendingChannel(Node source, Lightning.LightningClient client,
return result;
}


/// <summary>
/// Gets UTXOs confirmed from the wallet of the request
/// </summary>
Expand Down

0 comments on commit 17e94d6

Please sign in to comment.