Copy import { Transaction, PrivateKey, P2PKH, ARC } from '@bsv/sdk'
/**
* Basic Transaction Broadcaster
*
* Broadcast single, independent transactions using SDK's built-in broadcast
*/
class TransactionBroadcaster {
private arc?: ARC
constructor(arcUrl?: string, apiKey?: string) {
// Optional: Configure specific ARC instance
// If not provided, tx.broadcast() will use default broadcaster
if (arcUrl) {
this.arc = new ARC(arcUrl, { apiKey })
}
}
/**
* Broadcast a single transaction
* Uses SDK's tx.broadcast() method
*/
async broadcastTransaction(tx: Transaction): Promise<BroadcastResult> {
try {
console.log('Broadcasting transaction...')
console.log('Transaction ID:', tx.id('hex'))
console.log('Size:', tx.toHex().length / 2, 'bytes')
// Broadcast using SDK's built-in broadcast method
// Pass ARC instance if configured, otherwise uses default
const response = this.arc
? await tx.broadcast(this.arc)
: await tx.broadcast()
const result: BroadcastResult = {
txid: response.txid,
status: response.status,
timestamp: Date.now(),
blockHash: response.blockHash,
blockHeight: response.blockHeight
}
console.log('Transaction broadcast successful')
console.log('Status:', result.status)
return result
} catch (error) {
throw new Error(`Broadcast failed: ${error.message}`)
}
}
/**
* Broadcast and wait for confirmation
*/
async broadcastAndWait(
tx: Transaction,
maxWaitTime: number = 60000 // 60 seconds default
): Promise<BroadcastResult> {
try {
const result = await this.broadcastTransaction(tx)
console.log('Waiting for confirmation...')
const startTime = Date.now()
while (Date.now() - startTime < maxWaitTime) {
const status = await this.checkTransactionStatus(result.txid)
if (status.status === 'MINED') {
console.log('Transaction confirmed')
console.log('Block height:', status.blockHeight)
return status
}
// Wait 2 seconds before next check
await new Promise(resolve => setTimeout(resolve, 2000))
}
throw new Error('Transaction confirmation timeout')
} catch (error) {
throw new Error(`Broadcast and wait failed: ${error.message}`)
}
}
/**
* Check transaction status
*/
async checkTransactionStatus(txid: string): Promise<BroadcastResult> {
try {
if (!this.arc) {
throw new Error('ARC instance required for status checks. Provide arcUrl in constructor.')
}
const status = await this.arc.getTransactionStatus(txid)
return {
txid,
status: status.status,
timestamp: Date.now(),
blockHash: status.blockHash,
blockHeight: status.blockHeight
}
} catch (error) {
throw new Error(`Status check failed: ${error.message}`)
}
}
/**
* Broadcast multiple transactions
*/
async broadcastBatch(
transactions: Transaction[]
): Promise<BroadcastResult[]> {
try {
console.log('Broadcasting batch of', transactions.length, 'transactions')
const results: BroadcastResult[] = []
for (const tx of transactions) {
try {
const result = await this.broadcastTransaction(tx)
results.push(result)
} catch (error) {
console.error('Failed to broadcast tx:', tx.id('hex'), error.message)
results.push({
txid: tx.id('hex'),
status: 'FAILED',
timestamp: Date.now(),
error: error.message
})
}
}
console.log('Batch broadcast completed')
console.log('Successful:', results.filter(r => r.status !== 'FAILED').length)
console.log('Failed:', results.filter(r => r.status === 'FAILED').length)
return results
} catch (error) {
throw new Error(`Batch broadcast failed: ${error.message}`)
}
}
}
interface BroadcastResult {
txid: string
status: string
timestamp: number
blockHash?: string
blockHeight?: number
error?: string
}
/**
* Usage Example
*/
async function basicBroadcastExample() {
const broadcaster = new TransactionBroadcaster()
const privateKey = PrivateKey.fromRandom()
// Create transaction
const tx = new Transaction()
tx.addInput({
sourceTXID: 'source-tx...',
sourceOutputIndex: 0,
unlockingScriptTemplate: new P2PKH().unlock(privateKey),
sequence: 0xffffffff
})
tx.addOutput({
satoshis: 50000,
lockingScript: Script.fromAddress('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')
})
await tx.sign()
// Broadcast
const result = await broadcaster.broadcastTransaction(tx)
console.log('Result:', result)
// Or broadcast and wait for confirmation
const confirmedResult = await broadcaster.broadcastAndWait(tx, 30000)
console.log('Confirmed:', confirmedResult)
}