signPsbt

Request the signature and broadcast of a Partially Signed Bitcoin Transaction (PSBT)

Method name

signPsbt

Parameters

ParameterDescriptionRequiredType

hex

Hex of PSBT payload for signing

string

allowedSighash

Sighash types allowed for signing and finalizing inputs (defaults to type ALL)

SignatureHash[]

signAtIndex

Input index(es) that should be signed (defaults to sign all inputs)

number | number[]

network

Network for signing: mainnet, testnet, signet, sbtcDevenv or devnet

string

account

Index of account for signing (defaults to active account)

uint

broadcast

Whether to broadcast upon signing (default false)

Example request

Sign PSBT

interface SignPsbtRequestParams {
  hex: string;
  allowedSighash?: SignatureHash[];
  signAtIndex?: number | number[];
  network?: NetworkModes;         // default is user's current network
  account?: number;               // default is user's current account
  broadcast?: boolean;            // default is false - finalize/broadcast tx
}

const requestParams: SignPsbtRequestParams = { ...params };

const response = await window.LeatherProvider.request('signPsbt', requestParams);

Broadcast PSBT

Our API returns a PSBT back to the app, with the newly applied signatures. If your use-case is to spend the transaction immediately, you'll first need to finalize it, then broadcast it to the network.

See this example below how to extract a signed transaction from the PSBT

import * as btc from '@scure/btc-signer';
const hex = response.result.hex;
const tx = btc.Transaction.fromPSBT(hexToBytes(hex));
tx.finalize();
await broadcast(tx.hex);

Types and helper functions

interface BitcoinNetwork {
  bech32: string;
  pubKeyHash: number;
  scriptHash: number;
  wif: number;
}

const bitcoinTestnet: BitcoinNetwork = {
  bech32: 'tb',
  pubKeyHash: 0x6f,
  scriptHash: 0xc4,
  wif: 0xef,
};

const ecdsaPublicKeyLength = 33;

function ecdsaPublicKeyToSchnorr(pubKey: Uint8Array) {
  if (pubKey.byteLength !== ecdsaPublicKeyLength) throw new Error('Invalid public key length');
  return pubKey.slice(1);
}

function getTaprootPayment(publicKey: Uint8Array) {
  return btc.p2tr(ecdsaPublicKeyToSchnorr(publicKey), undefined, bitcoinTestnet);
}

Helper functions for Native SegWit PsbtRequestOptions

// Example request options for Native SegWit
function buildNativeSegwitPsbtRequest(pubKey: Uint8Array): PsbtRequestOptions {
  // SegWit pubKey used here is provided through auth response
  const p2wpkh = btc.p2wpkh(pubKey, bitcoinTestnet);

  const tx = new btc.Transaction();

  // Example inputs with included witness
  tx.addInput({
    index: 0,
    txid: '15f34b3bd2aab555a003cd1c6959ac09b36239c6af1cb16ff8198cef64f8db9c',
    witnessUtxo: {
      amount: BigInt(1000),
      script: p2wpkh.script,
    },
  });
  tx.addInput({
    index: 1,
    txid: 'dca5179afaa63eae112d8a97794de2d30dd823315bcabe6d8b8a6b98e3567705',
    witnessUtxo: {
      amount: BigInt(2000),
      script: p2wpkh.script,
    },
  });
  
  // Add outputs and/or other psbt data...

  const psbt = tx.toPSBT();

  // This example is choosing to sign all inputs bc no index(es) are provided
  return { hex: bytesToHex(psbt) };
}

Helper functions for Taproot PsbtRequestOptions

// Similar example request options for Taproot
function buildTaprootPsbtRequest(pubKey: Uint8Array): PsbtRequestOptions {
  // Taproot pubKey used here is provided through auth response
  const payment = getTaprootPayment(pubKey);

  const tx = new btc.Transaction();

  tx.addInput({
    index: 0,
    tapInternalKey: payment.tapInternalKey,
    txid: '15f34b3bd2aab555a003cd1c6959ac09b36239c6af1cb16ff8198cef64f8db9c',
    witnessUtxo: {
      amount: BigInt(1000),
      script: payment.script,
    },
  });
  tx.addInput({
    index: 1,
    tapInternalKey: payment.tapInternalKey,
    txid: 'dca5179afaa63eae112d8a97794de2d30dd823315bcabe6d8b8a6b98e3567705',
    witnessUtxo: {
      amount: BigInt(2000),
      script: payment.script,
    },
  });
  
  // Add outputs and/or other psbt data...

  const psbt = tx.toPSBT();

  return { hex: bytesToHex(psbt) };
}

Preview

Last updated