bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.6k stars 2.08k forks source link

How to sign a native P2WPKH ? #999

Closed youssefgh closed 6 years ago

youssefgh commented 6 years ago

Am creating a transaction that spends from a Bech32 address.

I checked the examples provided but there is no one that shows how to sign a native P2WPKH transaction

dabura667 commented 6 years ago

Pass along the scriptpubkey and it should work

youssefgh commented 6 years ago

Do you mean like this ?

var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash)
txb.sign(i, keyPair, redeemScript, null, unspent.value,scriptPubKey)

I tried also :

txb.sign(i, keyPair, null, null, unspent.value,scriptPubKey)

And :

txb.sign(i, keyPair, scriptPubKey, null, unspent.value)

But that doesn't work

dabura667 commented 6 years ago

P2WPKH shouldn’t have a redeemscript.

Your scriptpubkey should be the output of bitcoin.script.witnesspubkeyhash.output.encode(pubkeyhash)

youssefgh commented 6 years ago

I can now sign the transaction with :

let pubkeyhash = bitcoin.crypto.hash160(keyPair.getPublicKeyBuffer())
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(pubkeyhash)
txb.sign(i, keyPair, scriptPubKey, null, unspent.value)

But my transaction get rejected with error :

non-mandatory-script-verify-flag (Witness requires empty scriptSig)

Here is the raw TX:

01000000000101cbf8fc65d81048fed8209fd189f83e116f98ec1d9800036b8ae295f0db86d3f7000000001716001468d1144f117d5d369e9195aeb1e54d2c4f59668affffffff0240420f000000000017a9148f201c799fbf54ba5761021de0fdebfb7431e3cc87a44a89000000000016001468d1144f117d5d369e9195aeb1e54d2c4f59668a02483045022100a6c350913bfce4f81e64885215347a962ac4f99106b09558bad9d8577477ee0b022053ed4a4fd5f108aaaded04663f24017bf18390c66b70423cd7a2087a0d8d537e012103f6ed88de44738cd10555c2dfdce5f576d1d9c9145af6e2511dd340eeb645937e00000000

Thanks for your help @dabura667 👍

dabura667 commented 6 years ago

Don’t pass it to sign, pass it to addInput only

youssefgh commented 6 years ago

txb.addInput doesn't have a scriptPubKey param

Can you please provide a simple example ?

Thanks

dabura667 commented 6 years ago

Maybe the name is prevOutScript or something. prevout refers to the previous output and script is referring to the output script which is called scriptPubkey.

dabura667 commented 6 years ago
txb.addInput(txid, vout, null, scriptPubkey)
junderw commented 6 years ago
var bitcoin = require('bitcoinjs-lib')
var key = bitcoin.ECPair.fromWIF("cPfgEigfyffeCYFoEo1dyCfVGJf7tFu5E26ATR3Pq8dbifRyofT9",
                                  bitcoin.networks.testnet)
var scriptPubkey = bitcoin.script.witnessPubKeyHash.output.encode(
                       bitcoin.crypto.hash160(
                           key.getPublicKeyBuffer()
                       )
                   )
// <Buffer 00 14 d3 3f 86 f2 30 a4 ac bc 3f 3f 40 14 81 ce 3d 1a 0d b6 68 01>
var addr = bitcoin.address.fromOutputScript(scriptPubkey, bitcoin.networks.testnet)
// 'tb1q6vlcdu3s5jktc0elgq2grn3argxmv6qpq0lfm5'

var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet)

// txid, vout, sequence, previousOutputScriptPubkey
txb.addInput("a78a506e73e4a6b065d2865515be333d465b2f5080401c3fc406daee8a123787",
             0, null, scriptPubkey)

txb.addOutput("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF", 129800000)

// vin, key, redeemScript, hashType, witnessValue
txb.sign(0, key, null, null, 129900000)

var txhex = txb.build().toHex()

010000000001018737128aeeda06c43f1c4080502f5b463d33be155586d265b0a6e4736e508aa70000000000ffffffff014097bc070000000017a914a9974100aeee974a20cda9a2f545704a0ab54fdc870247304402207369f6c31501b0a298703e3ef5b1f7096a2f478c9154f2f992d40b5a536c3e73022000d068f99bc156a515bb9695c92432cf863567cba2b84ac602eb34c892d557b001210305f569040b1419b4327cdb0a947e042e295044be50422b9bb2e315eca370105400000000

Resulted in transaction: 9f2907308dd130194946ca3b2f4b92174bfedcd96ed6b3c8ddf0ed412dcb5ee1

youssefgh commented 6 years ago

@dabura667 @junderw that works perfectly It would be great to have this example as test case for future reference Thanks a lot for your help

dabura667 commented 6 years ago

Note to @dcousens:

This would be less complicated if ECPair and HDNode had a scriptType attribute

dcousens commented 6 years ago

@dabura667 move that discussion to #508.

dwasyluk commented 4 years ago

Can anyone please point me to an example of how to do this with the new bitcoin.payments API since bitcoin.script.witnessPubKeyHash.output.encode is no more? I'm trying:

 const pubkeyhash = bitcoin.crypto.hash160(keypair.publicKey);
 const scriptPubKey = bitcoin.payments.p2wpkh({ pubkey: keypair.publicKey}).output;
 txBuilder.addInput(vin_txids[0], 0, null, scriptPubKey);

But I'm still getting the 'witnesspubkeyhash not supported' error.

youssefgh commented 4 years ago

@dwasyluk how are you signing the transaction ? Please provide the complete code to reproduce your error

johnworthley commented 4 years ago

What is witnessValue?

johnworthley commented 4 years ago

What is witnessValue?

I see it is 'unspent.value' upon investigation. The scriptPubKey, parameter 6 of the sign method, is optional eh?

junderw commented 4 years ago

TransactionBuilder is marked for deprecation.

It is recommended you look at the integration tests to see how the PSBT class works and use that instead.