node-red-contrib-bdk 0.0.1
Node-RED nodes for Bitcoin Development Kit (BDK) integration with wallet configuration nodes
node-red-contrib-bdk
Node-RED nodes for Bitcoin Development Kit (BDK) integration.
Installation
npm install node-red-contrib-bdk
Configuration
Wallet Configuration Nodes
This package uses Wallet Configuration Nodes (similar to the Twitter node pattern) to manage wallet settings. Create wallet configuration nodes once and reuse them across multiple nodes.
Creating a Wallet Configuration
- Add a BDK Wallet configuration node to your flow
- Configure the wallet settings:
- Name: A friendly name for this wallet configuration
- Network: Select
mainnet,testnet,signet, orregtest - Bitcoin Descriptor: Optional watch-only wallet descriptor
- Account Index: BIP44 account index (default: 0)
- Mnemonic: Optional BIP39 mnemonic phrase (stored securely in credentials)
- Client Type: Choose
esplora(HTTP - recommended) orelectrum(TCP) - Server Provider: Choose
blockstreamormempool.space - Electrum URL: Optional Electrum server URL (only used when Client Type is
electrum) - Stop Gap: Number of consecutive unused addresses before stopping scan (default: 10)
Note: Either descriptor or mnemonic must be provided. If both are provided, descriptor takes precedence. If only mnemonic is provided, the descriptor will be automatically generated.
Using Wallet Configurations in Nodes
All BDK nodes allow you to select a wallet configuration:
- Open any BDK node (e.g., Generate Address, Sync, Get Balance)
- In the node configuration, select the wallet from the Wallet dropdown
- The node will use that wallet's configuration
Important: Wallet instances are cached, so sync state (transactions, balance, UTXOs) persists across all nodes using the same wallet configuration.
Optional: Global Defaults (settings.js)
You can optionally set global defaults in Node-RED's settings.js file. These defaults are used as fallbacks when creating wallet configurations:
module.exports = {
// ... other Node-RED settings ...
bdk: {
networkType: 'testnet', // Default network
clientType: 'esplora', // Default client type
electrumUrl: '', // Default Electrum URL
stopGap: 10 // Default stop gap
}
};
Note: These are only defaults. Each wallet configuration node can override these values.
Nodes
All nodes require selecting a wallet configuration node:
Core Wallet Operations
- bdk-wallet: Wallet configuration node (create this first)
- bdk-generate-address: Generate a new Bitcoin address for the wallet
- bdk-get-balance: Get the current wallet balance
- bdk-get-descriptor: Get the wallet descriptor
- bdk-sync: Synchronize wallet with blockchain
- bdk-list-transactions: List all transactions in the wallet
- bdk-get-utxos: Get all unspent transaction outputs (UTXOs)
Transaction Operations
- bdk-create-transaction: Create an unsigned PSBT (Partially Signed Bitcoin Transaction)
- bdk-sign-psbt: Sign a PSBT using the mnemonic from the wallet configuration
- bdk-finalize-psbt: Finalize a signed PSBT into a broadcastable transaction
- bdk-decode-psbt: Decode a PSBT and return detailed information
- bdk-broadcast: Broadcast a finalized transaction to the Bitcoin network
Usage Examples
Basic Flow: Generate Address and Check Balance
Create a BDK Wallet configuration node:
- Set Network to
testnet - Enter your mnemonic (or descriptor)
- Name it "My Test Wallet"
- Set Network to
Add a Generate Address node:
- Select "My Test Wallet" from the Wallet dropdown
- Configure address index and chain (external/internal)
Add a Get Balance node:
- Select the same "My Test Wallet" from the Wallet dropdown
- Connect it to receive messages
Add a Sync node:
- Select "My Test Wallet" from the Wallet dropdown
- This will sync the wallet with the blockchain before checking balance
Transaction Flow: Create, Sign, and Broadcast
Create a BDK Wallet configuration node with a mnemonic (required for signing)
Create Transaction node:
- Select your wallet
- Input:
msg.payload.recipient(address) andmsg.payload.amount(in satoshis)
Sign PSBT node:
- Select the same wallet (must have mnemonic configured)
- Input:
msg.payload.psbtfrom Create Transaction node
Finalize PSBT node:
- Select the same wallet
- Input:
msg.payload.psbtfrom Sign PSBT node
Broadcast node:
- Select the same wallet
- Input:
msg.payload.hexormsg.payload.psbtfrom Finalize PSBT node
Input/Output Format
Generate Address
Input: Any message (address index and chain can be overridden via msg.payload.index and msg.payload.chain)
Output:
{
address: "bc1...",
index: 0,
chain: "external",
scriptPubkey: "..."
}
Get Balance
Input: Any message
Output:
{
total: "1000000", // Total balance in satoshis (string)
spendable: "1000000", // Spendable balance (currently same as total)
unconfirmed: "0", // Unconfirmed balance (currently not calculated)
confirmed: "1000000", // Confirmed balance (currently same as total)
balanceString: "1000000 sats"
}
Note: Balance is calculated from UTXOs using wallet.list_unspent(). Confirmed/unconfirmed distinction is not yet implemented - all UTXOs are currently counted as confirmed.
Sync
Input: Any message
Output:
{
synced: true,
transactions: 5, // Number of transactions found
balance: "1000000" // Total balance in satoshis (string)
}
Note: Sync uses wallet.start_full_scan() and EsploraClient.full_scan() to synchronize the wallet with the blockchain. The stopGap parameter (default: 10) determines how many consecutive unused addresses to scan before stopping. Balance is calculated from UTXOs after syncing.
List Transactions
Input: Any message
Output:
{
transactions: [
{
txid: "...",
received: 1000000, // bigint or number
sent: 500000, // bigint or number
fee: "1000", // string or null
confirmationTime: {
height: 123456,
timestamp: 1234567890
} // null if unconfirmed
}
],
count: 1
}
Note: Transactions are retrieved using wallet.listTransactions(false). The confirmationTime field will be null for unconfirmed transactions. To check if a transaction is confirmed, verify that confirmationTime is not null.
Get UTXOs
Input: Any message
Output:
{
utxos: [
{
outpoint: "txid:vout",
txid: "...",
vout: 0,
value: "1000000", // Value in satoshis (string)
scriptPubkey: "...", // Hex-encoded script pubkey
confirmationTime: null // Not available directly on UTXO
}
],
count: 1
}
Note: UTXOs are retrieved using wallet.list_unspent(). Confirmation status is not available directly on the UTXO object. To check if a UTXO is confirmed, use the transaction ID (txid) with the List Transactions node to get the transaction's confirmation status.
Create Transaction
Input:
{
recipient: "bc1...", // or address
amount: "1000000", // in satoshis
feeRate: 1.0 // optional, sat/vB (default: 1.0)
}
Output:
{
psbt: "cHNidP8...",
message: "PSBT created. Use sign-psbt action to sign it."
}
Sign PSBT
Input:
{
psbt: "cHNidP8..." // or psbtString
}
Output:
{
psbt: "cHNidP8...",
signed: true,
message: "PSBT signed. Use finalize-psbt and broadcast actions to complete."
}
Finalize PSBT
Input:
{
psbt: "cHNidP8..." // or psbtString
}
Output:
{
txid: "...",
hex: "01000000...",
psbt: "cHNidP8...",
finalized: true
}
Broadcast
Input:
{
hex: "01000000...", // or transaction
psbt: "cHNidP8..." // or psbtString (will be finalized if hex not provided)
}
Output:
{
txid: "...",
broadcast: true
}
Network Configuration
Testnet (Default)
- Network:
testnet - Esplora URL:
https://blockstream.info/testnet/api - Use for testing and development
Mainnet
- Network:
mainnet - Esplora URL:
https://blockstream.info/api - Use for production with real funds
Signet
- Network:
signet - Esplora URL:
https://mempool.space/signet/api - Use for testing with a controlled network
Regtest
- Network:
regtest - URL:
http://localhost:3000/api - Use for local development with a local Bitcoin node
Security Notes
Mnemonic Storage: Mnemonics are stored securely in Node-RED's credential system and are never exposed in flow files.
Multiple Wallets: You can create multiple wallet configuration nodes for different wallets or networks. Each wallet maintains its own cached state.
Wallet State Persistence: Wallet instances are cached, so sync state (transactions, balance, UTXOs) persists across all nodes using the same wallet configuration. This means:
- Sync once, use balance/transactions in multiple nodes
- State is shared across nodes using the same wallet config
- State persists until Node-RED restarts or wallet config is updated
Never Commit Secrets: Never commit wallet configurations with real mnemonics to version control. Use Node-RED's credential system (which stores credentials separately from flow files).
Troubleshooting
"BDK Wallet configuration not selected"
- Make sure you've created a BDK Wallet configuration node
- Select the wallet in the node's configuration dialog
"Sync failed: endpoint not found" or "Sync failed: fetch failed"
- Check that the Esplora server is accessible
- Verify the network type matches the URL (testnet vs signet vs mainnet)
- Ensure the wallet descriptor/mnemonic is valid
- In standalone Node.js environments, WASM fetch may have limitations - sync works best in Node-RED environment
"Mnemonic required to sign PSBT"
- Make sure the selected wallet configuration has a mnemonic set
- Mnemonics are stored in credentials, so check the wallet config node's credentials
Wallet state not updating
- Run the Sync node to update wallet state
- Wallet state is cached per wallet configuration
- Multiple nodes using the same wallet config share the same state
Transactions always showing as unconfirmed
- Make sure you've run the Sync node to update wallet state
- Confirmation status is determined by the
confirmationTimefield in transaction objects - If
confirmationTimeisnull, the transaction is unconfirmed - Check that the Esplora server is properly synced with the blockchain
- Transactions use
wallet.listTransactions(false)which returns transactions withconfirmationTimepopulated for confirmed transactions
"Cannot find module '@bitcoindevkit/bdk-wallet-node'"
- Run
npm installin the package directory - If using Node-RED, also install in Node-RED's global
node_modules:cd ~/.node-red && npm install @bitcoindevkit/bdk-wallet-node
Transactions always showing as unconfirmed
- Make sure you've run the Sync node to update wallet state
- Confirmation status is determined by
confirmationTimefield in transaction objects - If
confirmationTimeisnull, the transaction is unconfirmed - Check that the Esplora server is properly synced with the blockchain
"Cannot find module '@bitcoindevkit/bdk-wallet-node'"
- Run
npm installin the package directory - If using Node-RED, also install in Node-RED's global
node_modules:cd ~/.node-red && npm install @bitcoindevkit/bdk-wallet-node
License
See LICENSE file for details.