From 24e5cc061699cf66e63df7b371d4d1171646d529 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 12 Nov 2021 12:39:56 +0900 Subject: [PATCH] Add Taproot example --- CHANGELOG.md | 13 +++++ README.md | 7 +-- test/integration/taproot.md | 111 ++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 test/integration/taproot.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e1eb7..f7d8f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 6.0.0 +__removed__ +- bip32: Removed the re-export. Please add as dependency to your app instead. +- ECPair: Please use bip32 moving forward. ecpair package was created for those who need it. +- TransactionBuilder: Any internal files used only in TB (classify, templates, etc.) were also removed. + +__added__ +- taproot segwit v1 address support (bech32m) via address module (#1676) +- hashForWitnessV1 method on Transaction class (#1745) + +__fixed__ +- Transaction version read/write differed. (#1717) + # 5.2.0 __changed__ - Updated PSBT to allow for witnessUtxo and nonWitnessUtxo simultaneously (Re: segwit psbt bug) (#1563) diff --git a/README.md b/README.md index d974624..9389a73 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # BitcoinJS (bitcoinjs-lib) -[![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) -[![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) - -[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) +[![Github CI](https://github.com/bitcoinjs/bitcoinjs-lib/actions/workflows/main_ci.yml/badge.svg)](https://github.com/bitcoinjs/bitcoinjs-lib/actions/workflows/main_ci.yml) [![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) A javascript Bitcoin library for node.js and browsers. Written in TypeScript, but committing the JS files to verify. @@ -94,6 +91,8 @@ The below examples are implemented as integration tests, they should be very eas Otherwise, pull requests are appreciated. Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). +- [Taproot Key Spend](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/taproot.md) + - [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts) - [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts) - [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts) diff --git a/test/integration/taproot.md b/test/integration/taproot.md new file mode 100644 index 0000000..2db6eef --- /dev/null +++ b/test/integration/taproot.md @@ -0,0 +1,111 @@ +# Taproot + +A simple keyspend example that is possible with the current API is below. + +## Current state of taproot support + +- [x] segwit v1 address support via bech32m +- [x] segwit v1 sighash calculation on Transaction class + +## TODO + +- [ ] p2tr payment API to make script spends easier +- [ ] Support within the Psbt class + +## Example + +### Requirements +- npm dependencies + - bitcoinjs-lib v6.x.x + - bip32 v3.x.x + - tiny-secp256k1 v2.x.x + - regtest-client vx.x.x +- local regtest-server docker container running + - `docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server` +- node >= v14 + +```js +const crypto = require('crypto'); + +// bitcoinjs-lib v6 +const bitcoin = require('bitcoinjs-lib'); +// bip32 v3 wraps tiny-secp256k1 +const BIP32Wrapper = require('bip32').default; +const RegtestUtils = require('regtest-client').RegtestUtils; +// tiny-secp256k1 v2 is an ESM module, so we can't "require", and must import async +import('tiny-secp256k1') + .then(async (ecc) => { + // End imports + + // set up dependencies + const APIPASS = process.env.APIPASS || 'satoshi'; + // docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server + const APIURL = process.env.APIURL || 'http://127.0.0.1:8080/1'; + const regtestUtils = new RegtestUtils({ APIPASS, APIURL }); + + const bip32 = BIP32Wrapper(ecc); + + const myKey = bip32.fromSeed(crypto.randomBytes(64), regtestUtils.network); + // scriptPubkey + const output = Buffer.concat([ + // witness v1, PUSH_DATA 32 bytes + Buffer.from([0x51, 0x20]), + // x-only pubkey (remove 1 byte y parity) + myKey.publicKey.slice(1, 33), + ]); + const address = bitcoin.address.fromOutputScript( + output, + regtestUtils.network + ); + // amount from faucet + const amount = 42e4; + // amount to send + const sendAmount = amount - 1e4; + // get faucet + const unspent = await regtestUtils.faucetComplex(output, amount); + + const tx = createSigned( + myKey, + unspent.txId, + unspent.vout, + sendAmount, + [output], + [amount] + ); + + const hex = tx.toHex(); + console.log('Valid tx sent from:'); + console.log(address); + console.log('tx hex:'); + console.log(hex); + await regtestUtils.broadcast(hex); + await regtestUtils.verify({ + txId: tx.getId(), + address, + vout: 0, + value: sendAmount, + }); + }) + .catch(console.error); + +// Function for creating signed tx +function createSigned(key, txid, vout, amountToSend, scriptPubkeys, values) { + const tx = new bitcoin.Transaction(); + tx.version = 2; + // Add input + tx.addInput(Buffer.from(txid, 'hex').reverse(), vout); + // Add output + tx.addOutput(scriptPubkeys[0], amountToSend); + const sighash = tx.hashForWitnessV1( + 0, // which input + scriptPubkeys, // All previous outputs of all inputs + values, // All previous values of all inputs + bitcoin.Transaction.SIGHASH_DEFAULT // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL) + ); + const signature = Buffer.from(key.signSchnorr(sighash)); + // witness stack for keypath spend is just the signature. + // If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value + tx.ins[0].witness = [signature]; + return tx; +} +``` \ No newline at end of file