Transaction Chains
Complete examples for creating transaction chains using the BEEF (Background Evaluation Extended Format) standard, enabling efficient SPV verification and zero-confirmation transaction chains.
Overview
Transaction chains allow you to create sequences of dependent transactions where outputs from one transaction are spent in subsequent transactions, all before any confirmations. The BEEF format packages these chains with their Merkle proofs, enabling efficient SPV verification without requiring the full blockchain.
Related SDK Components:
Basic Transaction Chain
import { Transaction, PrivateKey, P2PKH, BEEF } from '@bsv/sdk'
/**
* Basic Transaction Chain Builder
*
* Create a simple chain of transactions where each transaction
* spends outputs from the previous transaction.
*/
class TransactionChainBuilder {
/**
* Create a chain of transactions
*
* @param privateKey - Private key to sign transactions
* @param initialUTXO - Starting UTXO
* @param chainLength - Number of transactions in the chain
* @param amountPerTx - Amount to transfer in each transaction
* @returns Array of chained transactions
*/
async buildSimpleChain(
privateKey: PrivateKey,
initialUTXO: {
txid: string
vout: number
satoshis: number
script: Script
},
chainLength: number,
amountPerTx: number
): Promise<Transaction[]> {
try {
if (chainLength < 2) {
throw new Error('Chain length must be at least 2')
}
const chain: Transaction[] = []
let currentUTXO = initialUTXO
for (let i = 0; i < chainLength; i++) {
const tx = new Transaction()
// Add input from previous transaction (or initial UTXO)
tx.addInput({
sourceTXID: currentUTXO.txid,
sourceOutputIndex: currentUTXO.vout,
unlockingScriptTemplate: new P2PKH().unlock(privateKey),
sequence: 0xffffffff
})
// Calculate fee
const fee = 500
// Validate sufficient funds
if (currentUTXO.satoshis < amountPerTx + fee) {
throw new Error(`Insufficient funds at chain position ${i}`)
}
// Add output for next transaction in chain
const outputScript = new P2PKH().lock(privateKey.toPublicKey().toHash())
tx.addOutput({
satoshis: amountPerTx,
lockingScript: outputScript
})
// Add change output if needed
const change = currentUTXO.satoshis - amountPerTx - fee
if (change > 546) {
tx.addOutput({
satoshis: change,
lockingScript: outputScript
})
}
// Sign transaction
await tx.sign()
chain.push(tx)
// Update current UTXO for next iteration
currentUTXO = {
txid: tx.id('hex'),
vout: 0,
satoshis: amountPerTx,
script: outputScript
}
console.log(`Created transaction ${i + 1}/${chainLength} in chain`)
}
return chain
} catch (error) {
throw new Error(`Transaction chain building failed: ${error.message}`)
}
}
/**
* Create a branching chain (one input, multiple outputs, each spent separately)
*/
async buildBranchingChain(
privateKey: PrivateKey,
initialUTXO: {
txid: string
vout: number
satoshis: number
script: Script
},
branches: number
): Promise<{ root: Transaction; branches: Transaction[] }> {
try {
const outputScript = new P2PKH().lock(privateKey.toPublicKey().toHash())
// Create root transaction with multiple outputs
const rootTx = new Transaction()
rootTx.addInput({
sourceTXID: initialUTXO.txid,
sourceOutputIndex: initialUTXO.vout,
unlockingScriptTemplate: new P2PKH().unlock(privateKey),
sequence: 0xffffffff
})
// Calculate amount per branch
const fee = 500 + (branches * 50)
const amountPerBranch = Math.floor((initialUTXO.satoshis - fee) / branches)
if (amountPerBranch < 546) {
throw new Error('Not enough satoshis for branches')
}
// Create outputs for each branch
for (let i = 0; i < branches; i++) {
rootTx.addOutput({
satoshis: amountPerBranch,
lockingScript: outputScript
})
}
await rootTx.sign()
// Create branch transactions
const branchTxs: Transaction[] = []
for (let i = 0; i < branches; i++) {
const branchTx = new Transaction()
branchTx.addInput({
sourceTXID: rootTx.id('hex'),
sourceOutputIndex: i,
unlockingScriptTemplate: new P2PKH().unlock(privateKey),
sequence: 0xffffffff
})
const branchFee = 500
const branchOutput = amountPerBranch - branchFee
branchTx.addOutput({
satoshis: branchOutput,
lockingScript: outputScript
})
await branchTx.sign()
branchTxs.push(branchTx)
}
console.log(`Created branching chain: 1 root → ${branches} branches`)
return { root: rootTx, branches: branchTxs }
} catch (error) {
throw new Error(`Branching chain creation failed: ${error.message}`)
}
}
}
/**
* Usage Example
*/
async function basicChainExample() {
const builder = new TransactionChainBuilder()
const privateKey = PrivateKey.fromWif('your-wif-key')
const initialUTXO = {
txid: 'initial-txid...',
vout: 0,
satoshis: 100000,
script: new P2PKH().lock(privateKey.toPublicKey().toHash())
}
// Create a chain of 5 transactions
const chain = await builder.buildSimpleChain(privateKey, initialUTXO, 5, 15000)
console.log('Chain created:')
chain.forEach((tx, i) => {
console.log(` ${i + 1}. ${tx.id('hex')}`)
})
}BEEF Format Transaction Chain
Advanced Chain Patterns
Chain Validation and Management
Related Examples
See Also
SDK Components:
Transaction - Core transaction building
BEEF - BEEF format specification
SPV - SPV verification
Merkle Proofs - Merkle proof verification
Last updated
