or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

address.mdblocks.mdcrypto.mdindex.mdnetworks.mdpayments.mdpsbt.mdscripts.mdtransactions.mdutilities.md
tile.json

psbt.mddocs/

PSBT (Partially Signed Bitcoin Transactions)

Complete BIP174 implementation supporting all PSBT roles: Creator, Updater, Signer, Combiner, Input Finalizer, and Transaction Extractor. PSBTs enable collaborative transaction construction and signing across multiple parties and devices.

Core Types

interface PsbtTxInput extends TransactionInput {
  hash: Buffer;
}

interface PsbtTxOutput extends TransactionOutput {
  address: string | undefined;
}

interface TransactionInput {
  hash: string | Buffer;
  index: number;
  sequence?: number;
}

interface TransactionOutput {
  script: Buffer;
  value: number;
}

interface Signer {
  publicKey: Buffer;
  network?: any;
  sign(hash: Buffer, lowR?: boolean): Buffer;
  signSchnorr?(hash: Buffer): Buffer;
  getPublicKey?(): Buffer;
}

interface SignerAsync {
  publicKey: Buffer;
  network?: any;
  sign(hash: Buffer, lowR?: boolean): Promise<Buffer>;
  signSchnorr?(hash: Buffer): Promise<Buffer>;
  getPublicKey?(): Buffer;
}

interface HDSigner {
  publicKey: Buffer;
  fingerprint: Buffer;
  derivePath(path: string): HDSigner;
  sign(hash: Buffer): Buffer;
}

interface HDSignerAsync {
  publicKey: Buffer;
  fingerprint: Buffer;
  derivePath(path: string): HDSignerAsync;
  sign(hash: Buffer): Promise<Buffer>;
}

type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;

Capabilities

Psbt Creation

Create PSBTs from various sources or start with a new empty PSBT.

class Psbt {
  /**
   * Create PSBT from base64 string
   * @param data - Base64 encoded PSBT
   * @param opts - Optional network and fee rate settings
   * @returns New Psbt instance
   */
  static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt;
  
  /**
   * Create PSBT from hex string
   * @param data - Hex encoded PSBT
   * @param opts - Optional network and fee rate settings
   * @returns New Psbt instance
   */
  static fromHex(data: string, opts?: PsbtOptsOptional): Psbt;
  
  /**
   * Create PSBT from buffer
   * @param buffer - PSBT buffer
   * @param opts - Optional network and fee rate settings
   * @returns New Psbt instance
   */
  static fromBuffer(buffer: Buffer, opts?: PsbtOptsOptional): Psbt;
  
  /**
   * Create new empty PSBT
   * @param opts - Optional network and fee rate settings
   */
  constructor(opts?: PsbtOptsOptional);
}

interface PsbtOptsOptional {
  network?: Network;
  maximumFeeRate?: number;
}

Usage Examples:

import { Psbt, networks } from 'bitcoinjs-lib';

// Create new PSBT
const psbt = new Psbt({ network: networks.bitcoin });

// Load from base64
const psbtBase64 = 'cHNidP8BAHECAAAAAf...';
const loadedPsbt = Psbt.fromBase64(psbtBase64);

// Load from hex
const psbtHex = '70736274ff0100710200000001...';
const loadedPsbt2 = Psbt.fromHex(psbtHex);

// Set maximum fee rate (sat/vB)
psbt.setMaximumFeeRate(50);

PSBT Properties

Access basic PSBT information and transaction data.

/** Number of inputs in the PSBT */
get inputCount(): number;

/** Transaction version */
get version(): number;
set version(version: number);

/** Transaction locktime */
get locktime(): number;
set locktime(locktime: number);

/** Array of transaction inputs */
get txInputs(): PsbtTxInput[];

/** Array of transaction outputs */
get txOutputs(): PsbtTxOutput[];

Usage Examples:

const psbt = new Psbt();

console.log('Input count:', psbt.inputCount);
console.log('Version:', psbt.version);
console.log('Locktime:', psbt.locktime);

// Set transaction properties
psbt.version = 2;
psbt.locktime = 650000;

// Or use fluent interface
psbt.setVersion(2).setLocktime(650000);

Input Management

Add and manage PSBT inputs with all necessary data for signing.

/**
 * Add multiple inputs to PSBT
 * @param inputDatas - Array of input data objects
 * @returns This PSBT instance for chaining
 */
addInputs(inputDatas: PsbtInputExtended[]): this;

/**
 * Add single input to PSBT
 * @param inputData - Input data object
 * @returns This PSBT instance for chaining
 */
addInput(inputData: PsbtInputExtended): this;

/**
 * Set sequence number for existing input
 * @param inputIndex - Index of input to modify
 * @param sequence - New sequence number
 * @returns This PSBT instance for chaining
 */
setInputSequence(inputIndex: number, sequence: number): this;

interface PsbtInputExtended extends PsbtInput, TransactionInput {
  // Includes all BIP174 input fields plus transaction input data
}

Usage Examples:

import { Psbt, networks } from 'bitcoinjs-lib';

const psbt = new Psbt({ network: networks.bitcoin });

// Add legacy input (P2PKH)
psbt.addInput({
  hash: 'abc123def456...',
  index: 0,
  nonWitnessUtxo: Buffer.from('0100000001...', 'hex') // Full previous transaction
});

// Add SegWit input (P2WPKH)
psbt.addInput({
  hash: 'def456abc123...',
  index: 1,
  witnessUtxo: {
    script: Buffer.from('0014abcd...', 'hex'),
    value: 50000
  }
});

// Add Taproot input
psbt.addInput({
  hash: 'fedcba987654...',
  index: 0,
  witnessUtxo: {
    script: Buffer.from('5120abcd...', 'hex'),
    value: 100000
  },
  tapInternalKey: Buffer.from('abc123...', 'hex')
});

// Set custom sequence
psbt.setInputSequence(0, 0xfffffffd); // Enable RBF

Output Management

Add transaction outputs to the PSBT.

/**
 * Add multiple outputs to PSBT
 * @param outputDatas - Array of output data objects
 * @returns This PSBT instance for chaining
 */
addOutputs(outputDatas: PsbtOutputExtended[]): this;

/**
 * Add single output to PSBT
 * @param outputData - Output data object
 * @returns This PSBT instance for chaining
 */
addOutput(outputData: PsbtOutputExtended): this;

type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;

interface PsbtOutputExtendedAddress extends PsbtOutput {
  address: string;
  value: number;
}

interface PsbtOutputExtendedScript extends PsbtOutput {
  script: Buffer;
  value: number;
}

Usage Examples:

const psbt = new Psbt({ network: networks.bitcoin });

// Add output by address
psbt.addOutput({
  address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
  value: 50000
});

// Add output by script
psbt.addOutput({
  script: Buffer.from('76a914abcd...88ac', 'hex'),
  value: 25000
});

// Add multiple outputs
psbt.addOutputs([
  { address: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', value: 30000 },
  { address: '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy', value: 20000 }
]);

PSBT Signing

Sign inputs using various key types with support for different signature hash types.

/**
 * Sign all inputs with regular key pair
 * @param keyPair - Signer object
 * @param sighashTypes - Optional array of sighash types per input
 * @returns This PSBT instance for chaining
 */
signAllInputs(keyPair: Signer, sighashTypes?: number[]): this;

/**
 * Sign all inputs with regular key pair (async)
 * @param keyPair - Signer or async signer object
 * @param sighashTypes - Optional array of sighash types per input
 */
signAllInputsAsync(keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;

/**
 * Sign specific input with regular key pair
 * @param inputIndex - Index of input to sign
 * @param keyPair - Signer object
 * @param sighashTypes - Optional array of sighash types
 * @returns This PSBT instance for chaining
 */
signInput(inputIndex: number, keyPair: Signer, sighashTypes?: number[]): this;

/**
 * Sign specific input with regular key pair (async)
 * @param inputIndex - Index of input to sign
 * @param keyPair - Signer or async signer object
 * @param sighashTypes - Optional array of sighash types
 */
signInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;

Usage Examples:

import { Psbt, networks } from 'bitcoinjs-lib';

const psbt = new Psbt({ network: networks.bitcoin });
// ... add inputs and outputs ...

// Example signer (you need to implement this)
const signer = {
  publicKey: Buffer.from('03a34b...', 'hex'),
  sign: (hash: Buffer) => Buffer.from('3044...', 'hex') // ECDSA signature
};

// Sign all inputs
psbt.signAllInputs(signer);

// Sign specific input
psbt.signInput(0, signer);

// Sign with custom sighash type
psbt.signInput(1, signer, [Transaction.SIGHASH_SINGLE]);

// Async signing
await psbt.signAllInputsAsync(asyncSigner);

HD Key Signing

Sign with hierarchical deterministic keys supporting key derivation.

/**
 * Sign all inputs with HD key pair
 * @param hdKeyPair - HD signer object
 * @param sighashTypes - Optional array of sighash types per input
 * @returns This PSBT instance for chaining
 */
signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;

/**
 * Sign all inputs with HD key pair (async)
 * @param hdKeyPair - HD signer or async HD signer object
 * @param sighashTypes - Optional array of sighash types per input
 */
signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;

/**
 * Sign specific input with HD key pair
 * @param inputIndex - Index of input to sign
 * @param hdKeyPair - HD signer object
 * @param sighashTypes - Optional array of sighash types
 * @returns This PSBT instance for chaining
 */
signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;

/**
 * Sign specific input with HD key pair (async)
 * @param inputIndex - Index of input to sign
 * @param hdKeyPair - HD signer or async HD signer object
 * @param sighashTypes - Optional array of sighash types
 */
signInputHDAsync(inputIndex: number, hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;

Taproot Signing

Specialized signing methods for Taproot inputs supporting both key-path and script-path spending.

/**
 * Sign Taproot input with key pair
 * @param inputIndex - Index of input to sign
 * @param keyPair - Signer object
 * @param tapLeafHashToSign - Leaf hash for script-path spending
 * @param sighashTypes - Optional array of sighash types
 * @returns This PSBT instance for chaining
 */
signTaprootInput(inputIndex: number, keyPair: Signer, tapLeafHashToSign?: Buffer, sighashTypes?: number[]): this;

/**
 * Sign Taproot input with key pair (async)
 * @param inputIndex - Index of input to sign
 * @param keyPair - Signer or async signer object
 * @param tapLeafHash - Leaf hash for script-path spending
 * @param sighashTypes - Optional array of sighash types
 */
signTaprootInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, tapLeafHash?: Buffer, sighashTypes?: number[]): Promise<void>;

PSBT Finalization

Finalize inputs by constructing the final scriptSig and witness data.

/**
 * Finalize all inputs
 * @returns This PSBT instance for chaining
 */
finalizeAllInputs(): this;

/**
 * Finalize specific input
 * @param inputIndex - Index of input to finalize
 * @param finalScriptsFunc - Optional custom finalization function
 * @returns This PSBT instance for chaining
 */
finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this;

/**
 * Finalize Taproot input
 * @param inputIndex - Index of input to finalize
 * @param tapLeafHashToFinalize - Specific leaf hash to finalize
 * @param finalScriptsFunc - Optional custom finalization function
 * @returns This PSBT instance for chaining
 */
finalizeTaprootInput(inputIndex: number, tapLeafHashToFinalize?: Buffer, finalScriptsFunc?: FinalTaprootScriptsFunc): this;

Usage Examples:

const psbt = new Psbt({ network: networks.bitcoin });
// ... add inputs, outputs, and sign ...

// Finalize all inputs
psbt.finalizeAllInputs();

// Finalize specific input
psbt.finalizeInput(0);

// Finalize Taproot input for script-path spending
const leafHash = Buffer.from('abc123...', 'hex');
psbt.finalizeTaprootInput(0, leafHash);

Transaction Extraction

Extract the final signed transaction from the PSBT.

/**
 * Extract final transaction from PSBT
 * @param disableFeeCheck - Skip fee validation
 * @returns Final Transaction object
 * @throws Error if inputs are not finalized or fees are too high
 */
extractTransaction(disableFeeCheck?: boolean): Transaction;

/**
 * Calculate total fee for the transaction
 * @returns Fee in satoshis
 */
getFee(): number;

/**
 * Calculate fee rate for the transaction
 * @returns Fee rate in satoshis per virtual byte
 */
getFeeRate(): number;

Usage Examples:

const psbt = new Psbt({ network: networks.bitcoin });
// ... build, sign, and finalize PSBT ...

// Check fee before extraction
const fee = psbt.getFee();
const feeRate = psbt.getFeeRate();
console.log(`Fee: ${fee} sats (${feeRate} sat/vB)`);

// Extract final transaction
const finalTx = psbt.extractTransaction();
console.log('Final transaction:', finalTx.toHex());

// Broadcast finalTx.toHex() to network

PSBT Combination

Combine multiple PSBTs into a single PSBT.

/**
 * Combine this PSBT with other PSBTs
 * @param those - PSBTs to combine with this one
 * @returns This PSBT instance for chaining
 * @throws Error if PSBTs are incompatible
 */
combine(...those: Psbt[]): this;

/**
 * Clone this PSBT
 * @returns New PSBT instance with same data
 */
clone(): Psbt;

Usage Examples:

const psbt1 = Psbt.fromBase64('cHNidP8BAHECAAAAAf...');
const psbt2 = Psbt.fromBase64('cHNidP8BAHECAAAAAf...');
const psbt3 = Psbt.fromBase64('cHNidP8BAHECAAAAAf...');

// Combine PSBTs (psbt1 takes precedence in conflicts)
psbt1.combine(psbt2, psbt3);

// Clone for modification
const modifiedPsbt = psbt1.clone();

PSBT Validation

Validate signatures and check input/output properties.

/**
 * Validate all signatures in the PSBT
 * @param validator - Signature validation function
 * @returns True if all signatures are valid
 */
validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;

/**
 * Validate signatures for specific input
 * @param inputIndex - Index of input to validate
 * @param validator - Signature validation function
 * @param pubkey - Optional specific public key to validate
 * @returns True if signatures are valid
 */
validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean;

/**
 * Check if input has specific public key
 * @param inputIndex - Index of input to check
 * @param pubkey - Public key to search for
 * @returns True if input contains the public key
 */
inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean;

/**
 * Check if input has HD key
 * @param inputIndex - Index of input to check
 * @param root - HD key root to search for
 * @returns True if input contains derivation from the HD key
 */
inputHasHDKey(inputIndex: number, root: HDSigner): boolean;

PSBT Serialization

Convert PSBTs to various formats for storage and transmission.

/**
 * Serialize PSBT to buffer
 * @returns PSBT buffer
 */
toBuffer(): Buffer;

/**
 * Serialize PSBT to hex string
 * @returns Hex-encoded PSBT
 */
toHex(): string;

/**
 * Serialize PSBT to base64 string
 * @returns Base64-encoded PSBT
 */
toBase64(): string;

Usage Examples:

const psbt = new Psbt({ network: networks.bitcoin });
// ... build PSBT ...

// Export formats
const psbtBase64 = psbt.toBase64();
const psbtHex = psbt.toHex();
const psbtBuffer = psbt.toBuffer();

console.log('PSBT Base64:', psbtBase64);

PSBT Updates

Update PSBT global, input, and output data.

/**
 * Update global PSBT data
 * @param updateData - Global update data
 * @returns This PSBT instance for chaining
 */
updateGlobal(updateData: PsbtGlobalUpdate): this;

/**
 * Update input data
 * @param inputIndex - Index of input to update
 * @param updateData - Input update data
 * @returns This PSBT instance for chaining
 */
updateInput(inputIndex: number, updateData: PsbtInputUpdate): this;

/**
 * Update output data
 * @param outputIndex - Index of output to update
 * @param updateData - Output update data
 * @returns This PSBT instance for chaining
 */
updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this;

Advanced Usage

Hardware Wallet Integration

PSBTs are designed for hardware wallet workflows:

// 1. Create PSBT on online computer
const psbt = new Psbt({ network: networks.bitcoin });
psbt.addInput({/* input data */});
psbt.addOutput({/* output data */});

// 2. Export for hardware wallet
const psbtForHardware = psbt.toBase64();

// 3. Sign on hardware wallet (this happens externally)
// const signedPsbtBase64 = hardwareWallet.sign(psbtForHardware);

// 4. Import signed PSBT
const signedPsbt = Psbt.fromBase64(signedPsbtBase64);

// 5. Finalize and extract
signedPsbt.finalizeAllInputs();
const finalTx = signedPsbt.extractTransaction();

Multi-Party Signing

PSBTs enable collaborative signing:

// Party 1: Create and partially sign
const psbt = new Psbt({ network: networks.bitcoin });
// ... add inputs and outputs ...
psbt.signInput(0, party1Signer);

// Party 2: Add their signature
const psbtBase64 = psbt.toBase64();
const party2Psbt = Psbt.fromBase64(psbtBase64);
party2Psbt.signInput(0, party2Signer);

// Combine signatures
const finalPsbt = Psbt.fromBase64(psbt.toBase64());
finalPsbt.combine(party2Psbt);

Types

interface Network {
  messagePrefix: string;
  bech32: string;
  bip32: { public: number; private: number };
  pubKeyHash: number;
  scriptHash: number;
  wif: number;
}

type FinalScriptsFunc = (
  inputIndex: number,
  input: PsbtInput,
  script: Buffer,
  isSegwit: boolean,
  isP2SH: boolean,
  isP2WSH: boolean
) => {
  finalScriptSig: Buffer | undefined;
  finalScriptWitness: Buffer | undefined;
};

type FinalTaprootScriptsFunc = (
  inputIndex: number,
  input: PsbtInput,
  tapLeafHashToFinalize?: Buffer
) => {
  finalScriptWitness: Buffer | undefined;
};