PSBTs or partially signed Bitcoin transactions is a standard that allows unsigned or partially signed transactions to be transported for signing by multiple parties.
Here we will show examples of creating partially signed Bitcoin transactions using the light-weight and audited Bitcoin javascript library scure-btc-signer.
Creating a transaction with a wrapped-segwit (P2SH-P2WPHK) address
import*as btc from'micro-btc-signer'import { hex, base64 } from'@scure/base'constbitcoinTestnet= { bech32:'tb', pubKeyHash:0x6f, scriptHash:0xc4, wif:0xef,}// You can use any public Bitcoin API to retrieve unspent outputsconstoutput= {"tx_hash":"f39d37ec885de70c598648a2f80f103e1cdf34f7021ddfcb22216b7076169226","block_height":780179,"tx_input_n":-1,"tx_output_n":1,"value":300000,"ref_balance":22681,"spent":false,"confirmations":123,"confirmed":"2023-03-10T10:02:21Z","double_spend":false}constpublicKey=hex.encode("02818b7ff740a40f311d002123087053d5d9e0e1546674aedb10e15a5b57fd3985")constp2wpkh=btc.p2wpkh(publicKey, bitcoinTestnet);constp2sh=btc.p2sh(p2wpkh, bitcoinTestnet);tx.addInput({ txid:output.tx_hash, index:output.tx_output_n, witnessUtxo: { script:p2sh.script, amount:BigInt(output.value), }, redeemScript:p2sh.redeemScript,})// You can add more inputs here as necessary// Add outputsconstrecipient="tb1pzwa68q3udj0f7g5xtdakgecvf45dvssu66ry7y3at22w7vus20vq3sgw62"constchangeAddress="2NBfRKCUpafbatj5gV9T82uau3igdSf9BXJ"tx.addOutputAddress(recipient,BigInt(200000), bitcoinTestnet)tx.addOutputAddress(changeAddress,BigInt(80000), bitcoinTestnet)// Generate the base64 encoded PSBT that can be // passed to a compatible wallet for signingconstpsbt=tx.toPSBT(0)constpsbtB64=base64.encode(psbt0)
Creating a transaction with a Taproot (P2TR) address
constinternalPubKey=hex.decode("b9907521ddb85e0e6a37622b7c685efbdc8ae53a334928adbd12cf204ad4e717")constp2tr=btc.p2tr(internalPubKey,undefined, bitcoinTestnet)tx.addInput({ txid:output.tx_hash, index:output.tx_output_n, witnessUtxo: { script:p2tr.script, amount:BigInt(output.value), }, tapInternalKey: internalPubKey, sighashType:btc.SigHash.ALL})// You can add more inputs here as necessary// Add outputsconstrecipient="tb1pzwa68q3udj0f7g5xtdakgecvf45dvssu66ry7y3at22w7vus20vq3sgw62"constchangeAddress="2NBfRKCUpafbatj5gV9T82uau3igdSf9BXJ"tx.addOutputAddress(recipient,BigInt(200000), bitcoinTestnet)tx.addOutputAddress(changeAddress,BigInt(80000), bitcoinTestnet)// Generate the base64 encoded PSBT that can be // passed to a compatible wallet for signingconstpsbt=tx.toPSBT(0)constpsbtB64=base64.encode(psbt0)