bitcoinjs / bitcoinjs-lib

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

Example transaction with Psbt class #1597

Closed PraneshASP closed 3 years ago

PraneshASP commented 4 years ago

Currently I'm using the TranasctionBuilder class to sign the transaction. But, during execution I'm getting these two deprecation warnings.

Deprecation Warning: TransactionBuilder will be removed in the future. (v6.x.x or later) Please use the Psbt class instead. Examples of usage are available in the transactions-psbt.js integration test file on our Github. A high level explanation is available in the psbt.ts and psbt.js files as well.
DEPRECATED: TransactionBuilder sign method arguments will change in v6, please use the TxbSignArg interface

Is there any migration guide to move from Transaction Builder class to Psbt class?...also how to sign with the TxbSignArg interface?

Currently I'm creating transactions like this (for p2pkh addresses) :

txrefs.forEach( (transaction) => {
          txb.addInput(transaction.tx_hash, transaction.tx_output_n);
        });
        txb.addOutput(dest_address, amount_to_spend);
        for (var j = 0; j < txrefs.length; j++) {
          txb.sign(j, keyPair);
        }

How will the implementation with Psbt class and TxbSignArg interface affect this syntax?

educob commented 4 years ago

I hope this helps.

    let keyPair = root.derivePath('m/49'/0'/0'/0/0')
    const p2sh = bitcoin.payments.p2sh({
      redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network }),
      network
    })
    // recipients
    for(let i=0; i<recipients; i++) {
      psbt.addOutput({ address: addresses[i], value:  values[i] })
    }
      psbt.addInput({ hash: 'xxxx', index: 0,  
        redeemScript: p2sh.redeem.output,
        witnessUtxo: {
          script: p2sh.output, 
          value: 10000,
        }}
      )
    }
    psbt.signAllInputs(keyPair)
    psbt.finalizeAllInputs()
    const tx = psbt.extractTransaction()
i5hi commented 4 years ago

@educob Please help me understand this.

Correct me if I am wrong:

educob commented 4 years ago

No and no. Miner fee is the different between inputs amount and outputs amount. Change is given to the sender by explicitly adding an output (change amount = total_utxos_spent - total_sending - fees)

About the specifics in the redeems script and witness utxo the person to answer that is Jonathan. But as a 1st answer (I could be wrong), witness utxo is the unlocking script to spend the (old) utxos which are in this case a script hash (p2sh) of a segwit address (p2wpkh). And the redeemScript is the unlocking script of the pure segwit address nested in the script hash. An unlocking script is used along the locking script (created when the utxo is created) to confirm ownership of the funds.

You could read Jimmy Song's book Programming Bitcoin which is free in this github.

i5hi commented 4 years ago

Right, change and fee as outputs! Cheers for the response! Will check out the book! This has been gradually making more sense over the day.

i5hi commented 4 years ago

https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/fixtures/psbt.json

from this file, so far ive (wrongly?) concluded the equivalent bitcoin-core cli commands to be nonWitnessScript = gettransaction -> hex witnessScript = decoderawtransaction -> vin[n].scriptSig.hex redeemScript = decoderawtransaction -> txinwitness[n]

i5hi commented 4 years ago

wondering why value is a field for witnessUtxo

educob commented 4 years ago

"Right, change and fee as outputs!" Only change is an outout. Fees the amounto spent not send to outputs.

"nonWitnessScript = gettransaction -> hex". Tx is all the information combined not just nonWitnessScript. nonWitnessScript is for non-segwit addresses. Don't use them.

"wondering why value is a field for witnessUtxo". You are providing the unlocking script and the utxo amount. With that information the library can calculate fees, etc.

PraneshASP commented 4 years ago

I hope this helps.

    let keyPair = root.derivePath('m/49'/0'/0'/0/0')
    const p2sh = bitcoin.payments.p2sh({
      redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network }),
      network
    })
    // recipients
    for(let i=0; i<recipients; i++) {
      psbt.addOutput({ address: addresses[i], value:  values[i] })
    }
      psbt.addInput({ hash: 'xxxx', index: 0,  
        redeemScript: p2sh.redeem.output,
        witnessUtxo: {
          script: p2sh.output, 
          value: 10000,
        }}
      )
    }
    psbt.signAllInputs(keyPair)
    psbt.finalizeAllInputs()
    const tx = psbt.extractTransaction()

What if the address is in p2pkh format? will this work?? Thanks!

educob commented 4 years ago

It won't work. You have to take a look at the examples por p2pkh format.

PraneshASP commented 3 years ago

ok. It works :+1: . Thanks !