signPsbt

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

Method name

signPsbt

Parameters

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 you use-case is to broadcast the transaction, you'll first need to finalize it and submit 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