internal PSBTHDKeyMatch(T psbtCoin, IHDKey accountKey, KeyPath addressKeyPath, KeyValuePair <PubKey, RootedKeyPath> kv)
     : base(psbtCoin, accountKey, addressKeyPath, kv)
 {
     if (psbtCoin == null)
     {
         throw new ArgumentNullException(nameof(psbtCoin));
     }
     _Coin = psbtCoin;
 }
示例#2
0
 public HDKeyScriptPubKey(IHDKey hdKey, ScriptPubKeyType type)
 {
     if (hdKey == null)
     {
         throw new ArgumentNullException(nameof(hdKey));
     }
     this.hdKey = hdKey;
     this.type  = type;
 }
 /// <summary>
 /// Filter the keys which contains the <paramref name="accountKey"/> and <paramref name="accountKeyPath"/>.
 /// </summary>
 /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param>
 /// <param name="accountKeyPath">The account key path</param>
 /// <returns>HD Keys matching master root key</returns>
 public IEnumerable <PSBTHDKeyMatch> HDKeysFor(IHDKey accountKey, RootedKeyPath accountKeyPath = null)
 {
     if (accountKey == null)
     {
         throw new ArgumentNullException(nameof(accountKey));
     }
     accountKey = accountKey.AsHDKeyCache();
     return(Inputs.HDKeysFor(accountKey, accountKeyPath).OfType <PSBTHDKeyMatch>().Concat(Outputs.HDKeysFor(accountKey, accountKeyPath)));
 }
示例#4
0
        public async Task <PSBT> RequestPayjoin(PSBT originalTx, IHDKey accountKey, RootedKeyPath rootedKeyPath, HdPubKey changeHdPubKey, CancellationToken cancellationToken)
        {
            if (originalTx.IsAllFinalized())
            {
                throw new InvalidOperationException("The original PSBT should not be finalized.");
            }

            var optionalParameters = new PayjoinClientParameters();

            if (changeHdPubKey is { })
示例#5
0
 /// <summary>
 /// Deriving an HDKey is normally time consuming, this wrap the IHDKey in a new HD object which can cache derivations
 /// </summary>
 /// <param name="hdkey">The hdKey to wrap</param>
 /// <returns>An hdkey which cache derivations, of the parameter if it is already itself a cache</returns>
 public static IHDKey AsHDKeyCache(this IHDKey hdkey)
 {
     if (hdkey == null)
     {
         throw new ArgumentNullException(nameof(hdkey));
     }
     if (hdkey is HDKeyCache c)
     {
         return(c);
     }
     return(new HDKeyCache(hdkey));
 }
示例#6
0
 public RootedKeyPath(IHDKey masterKey, KeyPath keyPath)
 {
     if (masterKey == null)
     {
         throw new ArgumentNullException(nameof(masterKey));
     }
     if (keyPath == null)
     {
         throw new ArgumentNullException(nameof(keyPath));
     }
     _KeyPath           = keyPath;
     _MasterFingerprint = masterKey.GetPublicKey().GetHDFingerPrint();
 }
        /// <summary>
        /// Get the balance change if you were signing this transaction.
        /// </summary>
        /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param>
        /// <param name="masterFingerprint">The fingerprint of the master root key</param>
        /// <returns>The balance change</returns>
        public Money GetBalance(HDFingerprint?masterFingerprint, IHDKey accountKey)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            Money total = Money.Zero;

            foreach (var o in CoinsFor(masterFingerprint, accountKey))
            {
                var amount = o.GetCoin()?.Amount;
                if (amount == null)
                {
                    continue;
                }
                total += o is PSBTInput ? -amount : amount;
            }
            return(total);
        }
        /// <summary>
        /// Get the balance change if you were signing this transaction.
        /// </summary>
        /// <param name="accountHDScriptPubKey">The hdScriptPubKey used to generate addresses</param>
        /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param>
        /// <param name="accountKeyPath">The account key path</param>
        /// <returns>The balance change</returns>
        public Money GetBalance(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null)
        {
            if (accountHDScriptPubKey == null)
            {
                throw new ArgumentNullException(nameof(accountHDScriptPubKey));
            }
            Money total = Money.Zero;

            foreach (var o in CoinsFor(accountHDScriptPubKey, accountKey, accountKeyPath))
            {
                var amount = o.GetCoin()?.Amount;
                if (amount == null)
                {
                    continue;
                }
                total += o is PSBTInput ? -amount : amount;
            }
            return(total);
        }
        /// <summary>
        /// Add keypath information to this PSBT for each input or output involving it
        /// </summary>
        /// <param name="masterKey">The master key of the keypaths</param>
        /// <param name="paths">The path of the public keys with their expected scriptPubKey</param>
        /// <returns>This PSBT</returns>
        public PSBT AddKeyPath(IHDKey masterKey, params Tuple <KeyPath, Script>[] paths)
        {
            if (masterKey == null)
            {
                throw new ArgumentNullException(nameof(masterKey));
            }
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }

            masterKey = masterKey.AsHDKeyCache();
            foreach (var path in paths)
            {
                var key = masterKey.Derive(path.Item1);
                AddKeyPath(masterKey.GetPublicKey().GetHDFingerPrint(), key.GetPublicKey(), path.Item1, path.Item2);
            }
            return(this);
        }
示例#10
0
        public void TrySign(IHDKey masterKey, SigHash sigHash = SigHash.All)
        {
            if (masterKey == null)
            {
                throw new ArgumentNullException(nameof(masterKey));
            }
            var cache = masterKey.AsHDKeyCache();

            foreach (var hdk in this.HDKeysFor(masterKey))
            {
                if (((HDKeyCache)cache.Derive(hdk.KeyPath)).Inner is ExtKey k)
                {
                    Sign(k.PrivateKey, sigHash);
                }
                else
                {
                    throw new ArgumentException(paramName: nameof(masterKey), message: "This should be a private key");
                }
            }
        }
示例#11
0
        /// <summary>
        /// Sign all inputs which derive addresses from <paramref name="accountHDScriptPubKey"/> and that need to be signed by <paramref name="accountKey"/>.
        /// </summary>
        /// <param name="accountHDScriptPubKey">The address generator</param>
        /// <param name="accountKey">The account key with which to sign</param>
        /// <param name="accountKeyPath">The account key path (eg. [masterFP]/49'/0'/0')</param>
        /// <param name="sigHash">The SigHash</param>
        /// <returns>This PSBT</returns>
        public PSBT SignAll(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath, SigHash sigHash = SigHash.All)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            if (accountHDScriptPubKey == null)
            {
                throw new ArgumentNullException(nameof(accountHDScriptPubKey));
            }
            accountHDScriptPubKey = accountHDScriptPubKey.AsHDKeyCache();
            accountKey            = accountKey.AsHDKeyCache();
            Money total = Money.Zero;

            foreach (var o in Inputs.CoinsFor(accountHDScriptPubKey, accountKey, accountKeyPath))
            {
                o.TrySign(accountHDScriptPubKey, accountKey, accountKeyPath, sigHash);
            }
            return(this);
        }
        public PSBT SignAll(IHDKey masterKey, SigHash sigHash = SigHash.All)
        {
            if (masterKey == null)
            {
                throw new ArgumentNullException(nameof(masterKey));
            }
            var cache = masterKey.AsHDKeyCache();

            foreach (var o in Inputs.HDKeysFor(masterKey))
            {
                if (((HDKeyCache)cache.Derive(o.KeyPath)).Inner is ExtKey k)
                {
                    o.Coin.Sign(k.PrivateKey, sigHash);
                }
                else
                {
                    throw new ArgumentException(paramName: nameof(masterKey), message: "This should be a private key");
                }
            }
            return(this);
        }
        /// <summary>
        /// Rebase the keypaths.
        /// If a PSBT updater only know the child HD public key but not the root one, another updater knowing the parent master key it is based on
        /// can rebase the paths. If the PSBT is all finalized this operation is a no-op
        /// </summary>
        /// <param name="accountKey">The current account key</param>
        /// <param name="newRoot">The KeyPath with the fingerprint of the new root key</param>
        /// <returns>This PSBT</returns>
        public PSBT RebaseKeyPaths(IHDKey accountKey, RootedKeyPath newRoot)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            if (newRoot == null)
            {
                throw new ArgumentNullException(nameof(newRoot));
            }
            if (IsAllFinalized())
            {
                return(this);
            }
            accountKey = accountKey.AsHDKeyCache();
            var accountKeyFP = accountKey.GetPublicKey().GetHDFingerPrint();

            foreach (var o in HDKeysFor(accountKey).GroupBy(c => c.Coin))
            {
                if (o.Key is PSBTInput i && i.IsFinalized())
                {
                    continue;
                }
                foreach (var keyPath in o)
                {
                    o.Key.HDKeyPaths.Remove(keyPath.PubKey);
                    o.Key.HDKeyPaths.Add(keyPath.PubKey, newRoot.Derive(keyPath.RootedKeyPath.KeyPath));
                }
            }
            foreach (var xpub in GlobalXPubs.ToList())
            {
                if (xpub.Key.ExtPubKey.PubKey == accountKey.GetPublicKey())
                {
                    GlobalXPubs.Remove(xpub.Key);
                    GlobalXPubs.Add(xpub.Key, newRoot.Derive(xpub.Value.KeyPath));
                }
            }
            return(this);
        }
示例#14
0
        public static IHDKey Derive(this IHDKey hdkey, KeyPath keyPath)
        {
            if (hdkey == null)
            {
                throw new ArgumentNullException(nameof(hdkey));
            }
            if (keyPath == null)
            {
                throw new ArgumentNullException(nameof(keyPath));
            }
            if (keyPath.Indexes.Length == 0)
            {
                return(hdkey);
            }
            var key = hdkey;

            foreach (var index in keyPath.Indexes)
            {
                key = key.Derive(index);
            }
            return(key);
        }
        /// <summary>
        /// Rebase the keypaths.
        /// If a PSBT updater only know the child HD public key but not the root one, another updater knowing the parent master key it is based on
        /// can rebase the paths.
        /// </summary>
        /// <param name="accountKey">The current account key</param>
        /// <param name="accountKeyPath">The path from the master key to the accountKey</param>
        /// <param name="masterFingerprint">The master key fingerprint</param>
        /// <returns></returns>
        public PSBT RebaseKeyPaths(IHDKey accountKey, KeyPath accountKeyPath, HDFingerprint masterFingerprint)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            if (accountKeyPath == null)
            {
                throw new ArgumentNullException(nameof(accountKeyPath));
            }
            accountKey = accountKey.AsHDKeyCache();
            var accountKeyFP = accountKey.GetPublicKey().GetHDFingerPrint();

            foreach (var o in HDKeysFor(null, accountKey).GroupBy(c => c.Coin))
            {
                foreach (var keyPath in o)
                {
                    o.Key.HDKeyPaths.Remove(keyPath.PubKey);
                    o.Key.HDKeyPaths.Add(keyPath.PubKey, Tuple.Create(masterFingerprint, accountKeyPath.Derive(keyPath.KeyPath)));
                }
            }
            return(this);
        }
示例#16
0
        /// <summary>
        /// Rebase the keypaths.
        /// If a PSBT updater only know the child HD public key but not the root one, another updater knowing the parent master key it is based on
        /// can rebase the paths.
        /// </summary>
        /// <param name="accountKey">The current account key</param>
        /// <param name="newRoot">The KeyPath with the fingerprint of the new root key</param>
        /// <returns>This PSBT</returns>
        public PSBT RebaseKeyPaths(IHDKey accountKey, RootedKeyPath newRoot)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            if (newRoot == null)
            {
                throw new ArgumentNullException(nameof(newRoot));
            }
            accountKey = accountKey.AsHDKeyCache();
            var accountKeyFP = accountKey.GetPublicKey().GetHDFingerPrint();

            foreach (var o in HDKeysFor(accountKey).GroupBy(c => c.Coin))
            {
                foreach (var keyPath in o)
                {
                    o.Key.HDKeyPaths.Remove(keyPath.PubKey);
                    o.Key.HDKeyPaths.Add(keyPath.PubKey, newRoot.Derive(keyPath.RootedKeyPath.KeyPath));
                }
            }
            return(this);
        }
        /// <summary>
        /// Get the balance change if you were signing this transaction.
        /// </summary>
        /// <returns>The balance change</returns>
        public Money GetBalance(IHDKey masterKey)
        {
            if (masterKey == null)
            {
                throw new ArgumentNullException(nameof(masterKey));
            }
            var             masterFP        = masterKey.GetPublicKey().GetHDFingerPrint();
            Money           total           = Money.Zero;
            DerivationCache derivationCache = new DerivationCache(masterKey);

            foreach (var o in Inputs.OfType <PSBTCoin>().Concat(Outputs))
            {
                var amount = o.GetCoin()?.Amount;
                if (amount == null)
                {
                    continue;
                }
                if (o is PSBTInput)
                {
                    amount = -amount;
                }
                foreach (var hdk in o.HDKeyPaths)
                {
                    var pubkey  = hdk.Key;
                    var keyPath = hdk.Value.Item2;
                    var fp      = hdk.Value.Item1;

                    if ((fp == masterKey.GetPublicKey().GetHDFingerPrint() || fp == default) &&
                        (derivationCache.Derive(keyPath).GetPublicKey() == pubkey))
                    {
                        total += amount;
                    }
                }
            }
            return(total);
        }
示例#18
0
 internal IEnumerable <T> GetPSBTCoins(HDFingerprint?masterFingerprint, IHDKey accountKey)
 {
     return(GetHDKeys(masterFingerprint, accountKey)
            .Select(c => c.Coin)
            .Distinct());
 }
示例#19
0
 /// <summary>
 /// Filter the hd keys which contains a HD Key path matching this masterFingerprint/account key
 /// </summary>
 /// <param name="masterFingerprint">The master root fingerprint</param>
 /// <param name="accountKey">The account key (ie. 49'/0'/0')</param>
 /// <returns>HD Keys matching master root key</returns>
 public IEnumerable <PSBTHDKeyMatch <T> > HDKeysFor(HDFingerprint?masterFingerprint, IHDKey accountKey)
 {
     return(GetHDKeys(masterFingerprint, accountKey));
 }
示例#20
0
        internal IEnumerable <PSBTHDKeyMatch <T> > GetHDKeys(IHDScriptPubKey hdScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            accountKey     = accountKey.AsHDKeyCache();
            hdScriptPubKey = hdScriptPubKey?.AsHDKeyCache();
            var accountFingerprint = accountKey.GetPublicKey().GetHDFingerPrint();

            foreach (var c in this)
            {
                foreach (var match in c.HDKeysFor(hdScriptPubKey, accountKey, accountKeyPath, accountFingerprint))
                {
                    yield return((PSBTHDKeyMatch <T>)match);
                }
            }
        }
示例#21
0
 internal IEnumerable <T> GetPSBTCoins(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null)
 {
     return(GetHDKeys(accountHDScriptPubKey, accountKey, accountKeyPath)
            .Select(c => c.Coin)
            .Distinct());
 }
示例#22
0
 /// <summary>
 /// Filter the keys which contains the <paramref name="accountKey"/> and <paramref name="accountKeyPath"/>.
 /// </summary>
 /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param>
 /// <param name="accountKeyPath">The account key path</param>
 /// <returns>HD Keys matching master root key</returns>
 public IEnumerable <PSBTHDKeyMatch <T> > HDKeysFor(IHDKey accountKey, RootedKeyPath accountKeyPath = null)
 {
     return(GetHDKeys(null, accountKey, accountKeyPath));
 }
示例#23
0
 protected override PSBTHDKeyMatch CreateHDKeyMatch(IHDKey accountKey, KeyPath addressKeyPath, KeyValuePair <PubKey, RootedKeyPath> kv)
 {
     return(new PSBTHDKeyMatch <PSBTInput>(this, accountKey, addressKeyPath, kv));
 }
示例#24
0
 public void TrySign(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath, SigHash sigHash = SigHash.All)
 {
     TrySign(accountHDScriptPubKey, accountKey, accountKeyPath, Parent.Normalize(new SigningOptions(sigHash)));
 }
示例#25
0
        private async Task FetchTransactionDetails(DerivationSchemeSettings derivationSchemeSettings, WalletPSBTReadyViewModel vm, BTCPayNetwork network)
        {
            var psbtObject = PSBT.Parse(vm.SigningContext.PSBT, network.NBitcoinNetwork);

            if (!psbtObject.IsAllFinalized())
            {
                psbtObject = await ExplorerClientProvider.UpdatePSBT(derivationSchemeSettings, psbtObject) ?? psbtObject;
            }
            IHDKey        signingKey     = null;
            RootedKeyPath signingKeyPath = null;

            try
            {
                signingKey = new BitcoinExtPubKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }
            try
            {
                signingKey = signingKey ?? new BitcoinExtKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }

            try
            {
                signingKeyPath = RootedKeyPath.Parse(vm.SigningKeyPath);
            }
            catch { }

            if (signingKey == null || signingKeyPath == null)
            {
                var signingKeySettings = derivationSchemeSettings.GetSigningAccountKeySettings();
                if (signingKey == null)
                {
                    signingKey    = signingKeySettings.AccountKey;
                    vm.SigningKey = signingKey.ToString();
                }
                if (vm.SigningKeyPath == null)
                {
                    signingKeyPath    = signingKeySettings.GetRootedKeyPath();
                    vm.SigningKeyPath = signingKeyPath?.ToString();
                }
            }

            if (psbtObject.IsAllFinalized())
            {
                vm.CanCalculateBalance = false;
            }
            else
            {
                var balanceChange = psbtObject.GetBalance(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath);
                vm.BalanceChange       = ValueToString(balanceChange, network);
                vm.CanCalculateBalance = true;
                vm.Positive            = balanceChange >= Money.Zero;
            }
            vm.Inputs = new List <WalletPSBTReadyViewModel.InputViewModel>();
            foreach (var input in psbtObject.Inputs)
            {
                var inputVm = new WalletPSBTReadyViewModel.InputViewModel();
                vm.Inputs.Add(inputVm);
                var mine           = input.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
                var balanceChange2 = input.GetTxOut()?.Value ?? Money.Zero;
                if (mine)
                {
                    balanceChange2 = -balanceChange2;
                }
                inputVm.BalanceChange = ValueToString(balanceChange2, network);
                inputVm.Positive      = balanceChange2 >= Money.Zero;
                inputVm.Index         = (int)input.Index;
            }
            vm.Destinations = new List <WalletPSBTReadyViewModel.DestinationViewModel>();
            foreach (var output in psbtObject.Outputs)
            {
                var dest = new WalletPSBTReadyViewModel.DestinationViewModel();
                vm.Destinations.Add(dest);
                var mine           = output.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
                var balanceChange2 = output.Value;
                if (!mine)
                {
                    balanceChange2 = -balanceChange2;
                }
                dest.Balance     = ValueToString(balanceChange2, network);
                dest.Positive    = balanceChange2 >= Money.Zero;
                dest.Destination = output.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork)?.ToString() ?? output.ScriptPubKey.ToString();
            }

            if (psbtObject.TryGetFee(out var fee))
            {
                vm.Destinations.Add(new WalletPSBTReadyViewModel.DestinationViewModel
                {
                    Positive    = false,
                    Balance     = ValueToString(-fee, network),
                    Destination = "Mining fees"
                });
            }
            if (psbtObject.TryGetEstimatedFeeRate(out var feeRate))
            {
                vm.FeeRate = feeRate.ToString();
            }

            var sanityErrors = psbtObject.CheckSanity();

            if (sanityErrors.Count != 0)
            {
                vm.SetErrors(sanityErrors);
            }
            else if (!psbtObject.IsAllFinalized() && !psbtObject.TryFinalize(out var errors))
            {
                vm.SetErrors(errors);
            }
        }
示例#26
0
        internal IEnumerable <PSBTHDKeyMatch <T> > GetHDKeys(HDFingerprint?masterFingerprint, IHDKey accountKey)
        {
            if (accountKey == null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            accountKey = accountKey.AsHDKeyCache();
            var accountFingerprint = accountKey.GetPublicKey().GetHDFingerPrint();

            foreach (var c in this)
            {
                foreach (var match in c.HDKeysFor(masterFingerprint, accountKey, accountFingerprint))
                {
                    yield return((PSBTHDKeyMatch <T>)match);
                }
            }
        }
示例#27
0
 /// <summary>
 /// Filter the coins which contains a HD Key path matching this masterFingerprint/account key
 /// </summary>
 /// <param name="masterFingerprint">The master root fingerprint</param>
 /// <param name="accountKey">The account key (ie. 49'/0'/0')</param>
 /// <returns>Inputs with HD keys matching masterFingerprint and account key</returns>
 public IEnumerable <T> CoinsFor(HDFingerprint?masterFingerprint, IHDKey accountKey)
 {
     return(GetPSBTCoins(masterFingerprint, accountKey));
 }
示例#28
0
        public async Task <PSBT> RequestPayjoin(PSBT originalTx, IHDKey accountKey, RootedKeyPath rootedKeyPath, CancellationToken cancellationToken)
        {
            Guard.NotNull(nameof(originalTx), originalTx);
            if (originalTx.IsAllFinalized())
            {
                throw new InvalidOperationException("The original PSBT should not be finalized.");
            }

            var sentBefore  = -originalTx.GetBalance(ScriptPubKeyType.Segwit, accountKey, rootedKeyPath);
            var oldGlobalTx = originalTx.GetGlobalTransaction();

            if (!originalTx.TryGetEstimatedFeeRate(out var originalFeeRate) || !originalTx.TryGetVirtualSize(out var oldVirtualSize))
            {
                throw new ArgumentException("originalTx should have utxo information", nameof(originalTx));
            }

            var originalFee = originalTx.GetFee();
            var cloned      = originalTx.Clone();

            if (!cloned.TryFinalize(out var _))
            {
                return(null);
            }

            // We make sure we don't send unnecessary information to the receiver
            foreach (var finalized in cloned.Inputs.Where(i => i.IsFinalized()))
            {
                finalized.ClearForFinalize();
            }

            foreach (var output in cloned.Outputs)
            {
                output.HDKeyPaths.Clear();
            }

            cloned.GlobalXPubs.Clear();

            var request = new HttpRequestMessage(HttpMethod.Post, PaymentUrl)
            {
                Content = new StringContent(cloned.ToHex(), Encoding.UTF8, "text/plain")
            };

            HttpResponseMessage bpuResponse = await TorHttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

            if (!bpuResponse.IsSuccessStatusCode)
            {
                var errorStr = await bpuResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

                try
                {
                    var error = JObject.Parse(errorStr);
                    throw new PayjoinReceiverException((int)bpuResponse.StatusCode,
                                                       error["errorCode"].Value <string>(),
                                                       error["message"].Value <string>());
                }
                catch (JsonReaderException)
                {
                    // will throw
                    bpuResponse.EnsureSuccessStatusCode();
                    throw;
                }
            }

            var hexOrBase64 = await bpuResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

            var newPSBT = PSBT.Parse(hexOrBase64, originalTx.Network);

            // Checking that the PSBT of the receiver is clean
            if (newPSBT.GlobalXPubs.Any())
            {
                throw new PayjoinSenderException("GlobalXPubs should not be included in the receiver's PSBT");
            }

            if (newPSBT.Outputs.Any(o => o.HDKeyPaths.Count != 0) || newPSBT.Inputs.Any(o => o.HDKeyPaths.Count != 0))
            {
                throw new PayjoinSenderException("Keypath information should not be included in the receiver's PSBT");
            }

            if (newPSBT.CheckSanity() is IList <PSBTError> errors2 && errors2.Count != 0)
            {
                throw new PayjoinSenderException($"The PSBT of the receiver is insane ({errors2[0]})");
            }

            // Do not trust on inputs order because the payjoin server should shuffle them.
            foreach (var input in originalTx.Inputs)
            {
                var newInput = newPSBT.Inputs.FindIndexedInput(input.PrevOut);
                if (newInput is { })
示例#29
0
 public void TrySign(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, SigHash sigHash = SigHash.All)
 {
     TrySign(accountHDScriptPubKey, accountKey, null, sigHash);
 }
示例#30
0
 /// <summary>
 /// Filter the coins which contains the <paramref name="accountKey"/> and <paramref name="accountKeyPath"/> in the HDKeys and derive
 /// the same scriptPubKeys as <paramref name="accountHDScriptPubKey"/>.
 /// </summary>
 /// <param name="accountHDScriptPubKey">The hdScriptPubKey used to generate addresses</param>
 /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param>
 /// <param name="accountKeyPath">The account key path</param>
 /// <returns>Inputs with HD keys matching masterFingerprint and account key</returns>
 public IEnumerable <T> CoinsFor(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null)
 {
     return(GetPSBTCoins(accountHDScriptPubKey, accountKey, accountKeyPath));
 }