SkillAgentSearch skills...

Descriptors

A TypeScript library for parsing Bitcoin Descriptors, including Miniscript-based ones. Streamlines creating Partially Signed Bitcoin Transactions (PSBTs) from Descriptors. Features BIP32, single-signature, and Hardware Wallet signing capabilities, and facilitates finalizing transactions.

Install / Use

/learn @bitcoinerlab/Descriptors
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Bitcoin Descriptors Library

This library is designed to parse and create Bitcoin Descriptors, including Miniscript and Taproot script trees and generate Partially Signed Bitcoin Transactions (PSBTs). It also provides PSBT signers and finalizers for single-key, BIP32 and Hardware Wallets.

This library uses an underlying Bitcoin library for creating, signing & decoding transactions. Users can pick:

  • @bitcoinerlab/descriptors for the bitcoinjs-lib and bitcoinjs family of libraries: battle-tested and broadly used.
  • @bitcoinerlab/descriptors-scure for @scure/btc-signer and the noble/scure family of libraries: audited, fast and minimal.
  • @bitcoinerlab/descriptors-core as the low-level package used under the preset packages, intended for internal use.

In general, most users should pick one of the two preset packages and avoid using @bitcoinerlab/descriptors-core directly.

TL;DR (quick start)

Using @bitcoinerlab/descriptors-scure? See the scure variant right below.

npm install @bitcoinerlab/descriptors @bitcoinerlab/miniscript-policies

This quick example compiles a timelocked Miniscript policy, creates a descriptor address to fund, then builds, signs, and finalizes a PSBT that spends that funded UTXO and prints the final transaction hex.

import { ECPair, Output, Psbt, signers } from '@bitcoinerlab/descriptors'; // bitcoinjs-ready package

const ecpair = ECPair.makeRandom(); // Creates a signer for a single-key wallet

// Timelocked policy: signature + relative timelock (older)
const { miniscript } = compilePolicy('and(pk(@bob),older(10))');

const descriptor = `wsh(${miniscript.replace('@bob', toHex(ecpair.publicKey))})`;

// 1) Build the output description
const fundedOutput = new Output({ descriptor });
const address = fundedOutput.getAddress(); // Fund this address

// 2) Prepare PSBT input/output
const psbt = new Psbt();

const txHex = 'FUNDING_TX_HEX'; // hex of the tx that funded the address above
const vout = 0; // Output index (vout) of that UTXO within FUNDING_TX_HEX
const finalizeInput = fundedOutput.updatePsbtAsInput({ psbt, txHex, vout });

const recipient = new Output({
  descriptor: 'addr(bc1qgw6xanldsz959z45y4dszehx4xkuzf7nfhya8x)'
}); // Final address where we'll send the funds after timelock
recipient.updatePsbtAsOutput({ psbt, value: 10000n }); // input covers this+fees

// 3) Sign and finalize
signers.signECPair({ psbt, ecpair });
finalizeInput({ psbt });

console.log('Push this: ' + psbt.extractTransaction().toHex());
<details> <summary>Click to see the scure variant</summary>
npm install @bitcoinerlab/descriptors-scure @bitcoinerlab/miniscript-policies
import { Output, btc, secp256k1, signers } from '@bitcoinerlab/descriptors-scure';

const privKey = btc.utils.randomPrivateKeyBytes();
const pubkey = secp256k1.getPublicKey(privKey, true);

// Timelocked policy: signature + relative timelock (older)
const { miniscript } = compilePolicy('and(pk(@bob),older(10))');

const descriptor = `wsh(${miniscript.replace('@bob', toHex(pubkey))})`;

// 1) Build the output description
const fundedOutput = new Output({ descriptor });
const address = fundedOutput.getAddress(); // Fund this address

// 2) Prepare transaction input/output
const psbt = new btc.Transaction();

const txHex = 'FUNDING_TX_HEX'; // hex of the tx that funded the address above
const vout = 0; // Output index (vout) of that UTXO within FUNDING_TX_HEX
const finalizeInput = fundedOutput.updatePsbtAsInput({ psbt, txHex, vout });

const recipient = new Output({
  descriptor: 'addr(bc1qgw6xanldsz959z45y4dszehx4xkuzf7nfhya8x)'
});
recipient.updatePsbtAsOutput({ psbt, value: 10000n }); // input covers this+fees

// 3) Sign and finalize
signers.signPrivKey({ psbt, privKey });
finalizeInput({ psbt });

console.log('Push this: ' + psbt.hex);
</details>

Features

  • Parses and creates Bitcoin Descriptors (including those based on the Miniscript language).
  • Supports Taproot descriptors with trees: tr(KEY,TREE) (tapscript).
  • Generates Partially Signed Bitcoin Transactions (PSBTs).
  • Provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets (currently supports Ledger devices; more devices are planned).

Version Compatibility

Starting in 3.x, @bitcoinerlab/descriptors is aligned with the modern bitcoinjs stack (bitcoinjs-lib 7.x).

In practical terms, this means:

  • byte arrays are represented as Uint8Array;
  • satoshi values are represented as bigint.

If you need older bitcoinjs versions, keep using @bitcoinerlab/descriptors 2.x. If you want Taproot trees (tr(KEY,TREE)), use 3.x+.

Starting in 3.1.x, scure users can install @bitcoinerlab/descriptors-scure.

Concepts

This library has two main capabilities related to Bitcoin descriptors. Firstly, it can generate addresses and scriptPubKeys from descriptors. These addresses and scriptPubKeys can be used to receive funds from other parties. Secondly, the library is able to sign transactions and spend unspent outputs described by those same descriptors. In order to do this, the descriptors must first be set into a PSBT.

If you are not familiar with Bitcoin descriptors and partially signed Bitcoin transactions (PSBTs), click on the section below to expand and read more about these concepts.

<details> <summary>Concepts</summary>

Descriptors

In Bitcoin, a transaction consists of a set of inputs that are spent into a different set of outputs. Each input spends an output in a previous transaction. A Bitcoin descriptor is a string of text that describes the rules and conditions required to spend an output in a transaction.

For example, wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9) is a descriptor that describes a pay-to-witness-public-key-hash (P2WPKH) type of output with the specified public key. If you know the corresponding private key for the transaction for which this descriptor is an output, you can spend it.

Descriptors can express much more complex conditions, such as multi-party cooperation, time-locked outputs and more. These conditions can be expressed using the Bitcoin Miniscript language, which is a way of writing Bitcoin Scripts in a structured and more easily understandable way.

Partially Signed Bitcoin Transactions (PSBTs)

A PSBT (Partially Signed Bitcoin Transaction) is a format for sharing Bitcoin transactions between different parties.

PSBTs come in handy when working with descriptors, especially when using scripts, because they allow multiple parties to collaborate in the signing process. This is especially useful when using hardware wallets or other devices that require separate signatures or authorizations.

</details>

Usage

Before we dive in, it's worth mentioning that we have several comprehensive guides available covering different aspects of the library. These guides provide explanations and code examples in interactive playgrounds, allowing you to see the changes in the output as you modify the code. This hands-on learning experience, combined with clear explanations, helps you better understand how to use the library effectively. Check out the available guides here.

Furthermore, we've meticulously documented our API. For an in-depth look into Classes, functions and types, head over here.

For most users, install the package that matches your preferred Bitcoin library.

Bitcoinjs backend:

npm install @bitcoinerlab/descriptors

Scure/noble backend:

npm install @bitcoinerlab/descriptors-scure

If you plan to compile policy strings into Miniscript in your app, also install:

npm install @bitcoinerlab/miniscript-policies

The examples below keep the bitcoinjs stack visible by default. When backend-specific code differs, a collapsible scure variant is shown right below.

<details> <summary>Compatibility note for existing @bitcoinerlab/descriptors users</summary>

The root @bitcoinerlab/descriptors package still keeps a few 3.x compatibility shims, but they are deprecated and planned for removal in the next major release:

  • DescriptorsFactory() and DescriptorsFactory(ecc) on the root package
  • Root Ledger exports such as ledger, keyExpressionLedger, signers.signLedger, signers.signInputLedger, and scriptExpressions.*Ledger

For new code, prefer the preset top-level exports directly and use @bitcoinerlab/descriptors/ledger for Ledger helpers. DescriptorsFactory(...) on @bitcoinerlab/descriptors is kept only for 3.x backwards compatibility and is planned to stop being a public preset-package API in the next major release, including the custom ecc initialization path.

</details>

For a minimal end-to-end scure example, see test/integration/scure.ts.

The library can be split into four main parts:

  • The Output class is the central component for managing descriptors. It facilitates the creation of outputs to receive funds and enables the signing and finalization of PSBTs (Partially Signed Bitcoin Transactions) for spending UTXOs (Unspent Transaction Outputs).
  • PSBT signers and finalizers, which are used to manage the signing and finalization of PSBTs.
  • keyExpressions and scriptExpressions, which provide functions to create key and standard descriptor expressions (strings) from structured data.
  • Hardware wallet integration, which provides support for interacting with hardware wallets such as Ledger devices.
View on GitHub
GitHub Stars56
CategoryDevelopment
Updated1d ago
Forks17

Languages

TypeScript

Security Score

85/100

Audited on Mar 31, 2026

No findings