From f8b2b18c6e83026cd34245c22d5a955ad8f237cc Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Sat, 25 Apr 2020 17:19:24 +0200 Subject: [PATCH] Fix PJ (#1502) * Fix P2SH-P2WPKH case for Payjoin (Fix #1500) * fix p2sh issue Co-authored-by: nicolas.dorier --- .../PayJoin/PayJoinEndpointController.cs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs b/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs index 9f7267b3d..c58ea95b6 100644 --- a/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs +++ b/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs @@ -384,8 +384,10 @@ namespace BTCPayServer.Payments.PayJoin Money ourFeeContribution = Money.Zero; // We need to adjust the fee to keep a constant fee rate var txBuilder = network.NBitcoinNetwork.CreateTransactionBuilder(); - txBuilder.AddCoins(psbt.Inputs.Select(i => i.GetSignableCoin())); - txBuilder.AddCoins(selectedUTXOs.Select(o => o.Value.AsCoin(derivationSchemeSettings.AccountDerivation))); + var coins = psbt.Inputs.Select(i => i.GetSignableCoin()) + .Concat(selectedUTXOs.Select(o => o.Value.AsCoin(derivationSchemeSettings.AccountDerivation))).ToArray(); + + txBuilder.AddCoins(coins); Money expectedFee = txBuilder.EstimateFees(newTx, originalFeeRate); Money actualFee = newTx.GetFee(txBuilder.FindSpentCoins(newTx)); Money additionalFee = expectedFee - actualFee; @@ -458,7 +460,7 @@ namespace BTCPayServer.Payments.PayJoin originalPaymentData.ConfirmationCount = -1; originalPaymentData.PayjoinInformation = new PayjoinInformation() { - CoinjoinTransactionHash = newPsbt.GetGlobalTransaction().GetHash(), + CoinjoinTransactionHash = GetExpectedHash(newPsbt, sendersInputType, coins), CoinjoinValue = originalPaymentValue - ourFeeContribution, ContributedOutPoints = selectedUTXOs.Select(o => o.Key).ToArray() }; @@ -485,6 +487,27 @@ namespace BTCPayServer.Payments.PayJoin return Ok(newTx.ToHex()); } + private uint256 GetExpectedHash(PSBT psbt, ScriptPubKeyType? sendersInputType, Coin[] coins) + { + var tx = psbt.GetGlobalTransaction(); + if (sendersInputType is ScriptPubKeyType.Segwit) + return tx.GetHash(); + else if (sendersInputType is ScriptPubKeyType.SegwitP2SH) + { + for (int i = 0; i < psbt.Inputs.Count; i++) + { + + tx.Inputs[i].ScriptSig = PayToScriptHashTemplate.Instance.GenerateScriptSig(Array.Empty(), ((ScriptCoin)coins.Single(coin => coin.Outpoint == psbt.Inputs[i].PrevOut)).GetP2SHRedeem()); + } + return tx.GetHash(); + } + else + { + throw new NotSupportedException(); + } + + } + private JObject CreatePayjoinError(int httpCode, string errorCode, string friendlyMessage) { var o = new JObject();