Swift Bitcoin – Full node library

Jun 13, 2025 • Feature Specification

Partially Signed Bitcoin Transactions

PSBT support as defined by BIP174 is an important feature to have for any Bitcoin SDK. It serves as a compatibility layer between different software implementations as well as dedicated hardware devices such as wallets and signers.

While we hesitated at first to include this feature before Swift Bitcoin 0.1.0 is even out, a consideration was made that it would put the entire framework to the test – in a good way.

Given that PSBTs cover the entire lifecycle of a Bitcoin transaction it serves as validation that creation and signing flows can be built on top of the wallet API.

So far most of the effort was concentrated in passing the BIP's official test vectors. This ensures correct parsing and serialization as well as verifying preconditions for each role: creator, updater, signer, combiner, finalizer and extractor.

There's still room for improvement – specially on the ergonomics of the public interface – but the main functionality is already present.

import BitcoinPSBT

// Creator
// `tx` is a multisig transaction with with P2SH and P2SH-P2WSH inputs and 2 outputs.
var psbt = try PartiallySignedTx(tx) // Create from unsigned transaction
let psbtData = psbt.data // Serialize to pass it around

// Updater 1
psbt = try PartiallySignedTx(psbtData) // Parse from serialized format
psbt.update(input: 0, fund1)
psbt.update(input: 0, redeemScript: redeem0)
psbt.update(input: 0, pubkey0, path0)
psbt.update(input: 0, pubkey1, path1)

psbt.update(input: 1, fund0.outs[1])
psbt.update(input: 1, redeemScript: redeem1)
psbt.update(input: 1, witnessScript: witness)
psbt.update(input: 1, pubkey2, path2)
psbt.update(input: 1, pubkey3, path3)

psbt.update(out: 0, pubkey4, path4)
psbt.update(out: 1, pubkey5, path5)

let psbtData1 = psbt.data

// Second updater
psbt = try PartiallySignedTx(psbtData1)
psbt.update(input: 0, SighashType.all)
psbt.update(input: 1, SighashType.all)
let psbtData = psbt.data2

// Signer
psbt = try PartiallySignedTx(psbtData2)
try psbt.sign(input: 0, using: secretKey0)
try psbt.sign(input: 1, using: secretKey1)
let psbtData3 = psbt.data

// Second signer
psbt = try PartiallySignedTx(psbtData3)
try psbt.sign(input: 0, using: secretKey0)
try psbt.sign(input: 1, using: secretKey1)
let psbtData4 = psbt.data

// Combiner
psbt = try PartiallySignedTx(psbtData4)
psbt.combine(with: psbt2)
let psbtData5 = psbt.data

// Finalizer
psbt = try PartiallySignedTx(psbtData5)
psbt.finalize()
let psbtData6 = psbt.data

// Extractor
psbt = try PartiallySignedTx(psbtData6)
let tx = psbt.extractTx()

// Assuming we have a configured node.
…
node.sendTransaction(tx) // Broadcast signed transaction