Creating Transactions with Direct Interfaces
This guide demonstrates how to create Bitcoin SV transactions using the lower-level direct interfaces provided by the BSV TypeScript SDK. This approach gives you more control over transaction construction and is useful for specialized use cases where the WalletClient
abstraction isn't suitable.
When to Use Direct Interfaces
- When creating custom transaction types not supported by
WalletClient
- When you need precise control over UTXO selection
- When building specialized applications like data storage services that require custom optimization
- When integrating with systems that require direct management of transactions
- For educational purposes to understand the underlying transaction structure
Basic Transaction Construction
import { PrivateKey, P2PKH, Transaction } from '@bsv/sdk'
async function createBasicTransaction() {
// Create a private key
const privateKey = PrivateKey.fromRandom()
console.log(`Private key WIF: ${privateKey.toWif()}`)
// Derive the address
const address = privateKey.toAddress()
console.log(`Address: ${address.toString()}`)
// Create a new transaction
const tx = new Transaction()
// Add an output
tx.addOutput({
lockingScript: new P2PKH().lock(address),
satoshis: 1000
})
// Serialize the transaction
const txHex = tx.toHex()
console.log(`Transaction (hex): ${txHex}`)
// Get transaction ID as a hex string
const txid = Buffer.from(tx.id()).toString('hex')
console.log(`Transaction ID: ${txid}`)
}
Complete Transaction with Inputs and Outputs
For a complete transaction that can be broadcast, you need to add inputs, calculate fees, and sign it:
import { Transaction, PrivateKey, P2PKH, ARC } from '@bsv/sdk'
async function createCompleteTransaction() {
// Set up your wallet
const privateKey = PrivateKey.fromWif('your_private_key_here')
const myAddress = privateKey.toAddress()
const recipientAddress = 'recipient_address_here'
// You need the hex of the source transaction
const sourceTxHex = '...' // Hex string of the source transaction
// Create a transaction
const tx = new Transaction()
// Add the input
tx.addInput({
sourceTransaction: Transaction.fromHex(sourceTxHex),
sourceOutputIndex: 0, // The output index you want to spend
unlockingScriptTemplate: new P2PKH().unlock(privateKey)
})
// Add the recipient output
tx.addOutput({
lockingScript: new P2PKH().lock(recipientAddress),
satoshis: 100 // Amount to send
})
// Add the change output back to our address
tx.addOutput({
lockingScript: new P2PKH().lock(myAddress),
change: true // SDK will automatically calculate the change amount
})
// Calculate fee and sign the transaction
await tx.fee()
await tx.sign()
// Get the transaction hex ready for broadcasting
const signedTxHex = tx.toHex()
console.log(`Signed transaction hex: ${signedTxHex}`)
// Get the transaction ID
const txid = Buffer.from(tx.id()).toString('hex')
console.log(`Transaction ID: ${txid}`)
}
Broadcasting the Transaction
To broadcast your signed transaction:
import { ARC, NodejsHttpClient } from '@bsv/sdk'
import https from 'https'
async function broadcastTransaction(signedTx) {
// Create an HTTP client
const httpClient = new NodejsHttpClient(https)
// Initialize the ARC client
const arc = new ARC('https://api.arc.taal.com', {
apiKey: 'your_api_key_here',
httpClient,
deploymentId: 'your-deployment-id'
})
// Broadcast the transaction
const result = await signedTx.broadcast(arc)
console.log('Broadcast result:', result)
}
Key Implementation Details
When working with direct interfaces, remember these important details:
- Use
toWif()
(lowercase 'f') nottoWIF()
for private key WIF format - Use
toHex()
instead oftoString()
for transaction serialization - Transaction IDs need to be converted from byte arrays:
Buffer.from(tx.id()).toString('hex')
- For script objects, use
toHex()
ortoASM()
rather thantoString()
- Method chaining doesn't work well with current API - use separate method calls
Direct Creation vs WalletClient
Approach
Feature | Direct Creation | WalletClient |
---|---|---|
Control over transaction structure | High | Low |
Complexity | High | Low |
Recommended use case | Specialized applications | Production applications |
This guide focuses on direct transaction creation using low-level APIs, which gives you complete control over every aspect of the transaction. For simpler applications, consider using the WalletClient
approach covered in other tutorials.
Related Resources
- For simpler implementations, see the Creating Transactions with WalletClient tutorial
- Learn about Advanced Transaction Signing
- Explore HTTP Client Configuration for optimizing API requests