@tetherto/wdk-wallet-btc
Note: This package is currently in beta. Please test thoroughly in development environments before using in production.
A simple and secure package to manage BIP-84 (SegWit) wallets for the Bitcoin blockchain. This package provides a clean API for creating, managing, and interacting with Bitcoin wallets using BIP-39 seed phrases and Bitcoin-specific derivation paths.
🔍 About WDK
This module is part of the WDK (Wallet Development Kit) project, which empowers developers to build secure, non-custodial wallets with unified blockchain access, stateless architecture, and complete user control.
For detailed documentation about the complete WDK ecosystem, visit docs.wallet.tether.io.
🌟 Features
- BIP-39 Seed Phrase Support: Generate and validate BIP-39 mnemonic seed phrases
- Bitcoin Derivation Paths: Support for BIP-84 (Native SegWit) and BIP-44 (Legacy) derivation paths
- Multi-Account Management: Create and manage multiple accounts from a single seed phrase
- Transaction Management: Create, sign, and broadcast Bitcoin transactions
- UTXO Management: Track and manage unspent transaction outputs using Electrum servers
⬇️ Installation
To install the @tetherto/wdk-wallet-btc package, follow these instructions:
You can install it using npm:
🚀 Quick Start
Importing from @tetherto/wdk-wallet-btc
Creating a New Wallet
Note: This implementation uses BIP-84 derivation paths by default and generates Native SegWit (bech32) addresses. BIP-44 (legacy) addresses are also supported via the bip configuration option.
Important Note about Electrum Servers:
While the package defaults to electrum.blockstream.info if no host is specified, we strongly recommend configuring your own Electrum server for production use. Public servers like Blockstream's can be significantly slower (10-300x) and may fail when fetching transaction history for popular addresses with many transactions. For better performance, consider using alternative public servers like fulcrum.frznode.com for development, or set up your own Fulcrum server for production environments.
Managing Multiple Accounts
Methods
Note: This implementation generates Native SegWit (bech32) addresses by default. All accounts use BIP-84 derivation paths (m/84'/0'/account'/0/index for mainnet, m/84'/1'/account'/0/index for testnet/regtest).
Checking Balances
Account Balance
Important Notes:
getBalance() returns confirmed balance only (no unconfirmed balance option)
- There's no direct UTXO access method - UTXOs are managed internally
- Use
getTransfers() instead of getTransactionHistory() for transaction data
- Transfer objects include transaction ID, value, direction, fee, and block height information
Sending Transactions
Send Bitcoin and estimate fees using WalletAccountBtc. Uses Electrum servers for broadcasting.
Important Notes:
- Bitcoin transactions support single recipient only (no multiple recipients in one call)
- Fee rate is calculated automatically based on network conditions if not provided
- Transaction amounts and fees are always in satoshis (1 BTC = 100,000,000 satoshis)
sendTransaction() returns hash and fee properties
quoteSendTransaction() returns only the fee estimate
Message Signing and Verification
Sign messages using WalletAccountBtc. Verify messages using WalletAccountReadOnlyBtc (also available on WalletAccountBtc through inheritance).
Fee Management
Retrieve current fee rates using WalletManagerBtc. Rates are provided in satoshis per virtual byte (sat/vB).
Important Notes:
- Fee rates are fetched from mempool.space API
getFeeRates() returns only normal and fast fee rates (no economic or priority)
- Fee estimation is done via
quoteSendTransaction() method, not a separate estimateFee() method
- Fee rates are automatically calculated based on network conditions and UTXO selection
- Actual fees depend on transaction size (number of inputs/outputs) and current network congestion
Memory Management
Clear sensitive data from memory using dispose methods.
📚 API Reference
Table of Contents
WalletManagerBtc
The main class for managing Bitcoin wallets.
Extends WalletManager from @tetherto/wdk-wallet.
Constructor
Parameters:
seed (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
config (BtcWalletConfig, optional): Configuration object
network (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
bip (number, optional): BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)
client — one of:
- An
IBtcClient instance (pre-built client)
- A descriptor
{ type, clientConfig } where type is 'electrum', 'blockbook-http', or 'electrum-ws'
- An array of the above (for failover — tries each in order)
Example:
Methods
| Method | Description | Returns |
|---|
getAccount(index) | Returns a wallet account at the specified index | Promise<WalletAccountBtc> |
getAccountByPath(path) | Returns a wallet account at the specified BIP-84 derivation path | Promise<WalletAccountBtc> |
getFeeRates() | Returns current fee rates for transactions | Promise<{normal: bigint, fast: bigint}> |
dispose() | Disposes all wallet accounts, clearing private keys from memory | void |
getAccount(index)
Returns a wallet account at the specified index using BIP-84 derivation.
Parameters:
index (number, optional): The index of the account to get (default: 0)
Returns: Promise<WalletAccountBtc> - The wallet account
Example:
getAccountByPath(path)
Returns a wallet account at the specified BIP-84 derivation path.
Parameters:
path (string): The derivation path (e.g., "0'/0/0")
Returns: Promise<WalletAccountBtc> - The wallet account
Example:
getFeeRates()
Returns current fee rates from mempool.space API.
Returns: Promise<{normal: bigint, fast: bigint}> - Object containing fee rates in sat/vB
normal: Standard fee rate for confirmation within ~1 hour
fast: Higher fee rate for faster confirmation
Example:
dispose()
Disposes all wallet accounts and clears sensitive data from memory.
Returns: void
Example:
WalletAccountBtc
Represents an individual Bitcoin wallet account. Extends WalletAccountReadOnlyBtc and implements IWalletAccount from @tetherto/wdk-wallet.
Constructor
Parameters:
seed (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
path (string): Derivation path suffix (e.g., "0'/0/0")
config (BtcWalletConfig, optional): Configuration object (see WalletManagerBtc constructor for details)
Methods
| Method | Description | Returns |
|---|
getAddress() | Returns the account's Bitcoin address | Promise<string> |
getBalance() | Returns the confirmed account balance in satoshis | Promise<bigint> |
sendTransaction(options) | Sends a Bitcoin transaction | Promise<{hash: string, fee: bigint}> |
quoteSendTransaction(options) | Estimates the fee for a transaction | Promise<{fee: bigint}> |
getTransfers(options?) | Returns the account's transfer history | Promise<BtcTransfer[]> |
getTransactionReceipt(hash) | Returns a transaction's receipt | Promise<BtcTransaction | null> |
getMaxSpendable() | Returns the maximum spendable amount | Promise<{amount: bigint, fee: bigint, changeValue: bigint}> |
sign(message) | Signs a message with the account's private key | Promise<string> |
verify(message, signature) | Verifies a message signature | Promise<boolean> |
toReadOnlyAccount() | Creates a read-only version of this account | Promise<WalletAccountReadOnlyBtc> |
dispose() | Disposes the wallet account, clearing private keys from memory | void |
getAddress()
Returns the account's Bitcoin address (Native SegWit bech32 by default, or legacy if using BIP-44).
Returns: Promise<string> - The Bitcoin address
Example:
getBalance()
Returns the account's confirmed balance in satoshis.
Returns: Promise<bigint> - Balance in satoshis
Example:
sendTransaction(options)
Sends a Bitcoin transaction to a single recipient.
Parameters:
options (object): Transaction options
to (string): Recipient's Bitcoin address
value (number | bigint): Amount in satoshis
feeRate (number | bigint, optional): Fee rate in sat/vB (auto-estimated if not provided)
confirmationTarget (number, optional): Target blocks for confirmation (default: 1)
Returns: Promise<{hash: string, fee: bigint}> - Object containing hash and fee (in satoshis)
Example:
quoteSendTransaction(options)
Estimates the fee for a transaction without broadcasting it.
Parameters:
options (object): Same as sendTransaction options
to (string): Recipient's Bitcoin address
value (number | bigint): Amount in satoshis
feeRate (number | bigint, optional): Fee rate in sat/vB (auto-estimated if not provided)
confirmationTarget (number, optional): Target blocks for confirmation (default: 1)
Returns: Promise<{fee: bigint}> - Object containing estimated fee (in satoshis)
Example:
getTransfers(options?)
Returns the account's transfer history with detailed transaction information.
Parameters:
options (object, optional): Filter options
direction (string, optional): 'incoming', 'outgoing', or 'all' (default: 'all')
limit (number, optional): Maximum number of transfers (default: 10)
skip (number, optional): Number of transfers to skip (default: 0)
Returns: Promise<BtcTransfer[]> - Array of transfer objects
Example:
getTransactionReceipt(hash)
Returns a transaction's receipt if it has been included in a block.
Parameters:
hash (string): The transaction hash (64 hex characters)
Returns: Promise<BtcTransaction | null> - The transaction object, or null if not yet confirmed
Example:
getMaxSpendable()
Returns the maximum spendable amount that can be sent in a single transaction. The maximum spendable amount can differ from the wallet's total balance for several reasons:
- Transaction fees: Fees are subtracted from the total balance
- Uneconomic UTXOs: Small UTXOs where the fee to spend them exceeds their value are excluded
- UTXO limit: A transaction can include at most 200 inputs. Wallets with more UTXOs cannot spend their full balance in a single transaction.
- Dust limit: Outputs below the dust threshold (294 sats for SegWit, 546 sats for legacy) cannot be created
Returns: Promise<{amount: bigint, fee: bigint, changeValue: bigint}> - Maximum spendable result
Example:
sign(message)
Signs a message using the account's private key.
Parameters:
message (string): Message to sign
Returns: Promise<string> - Signature as base64 string
Example:
verify(message, signature)
Verifies a message signature using the account's public key.
Parameters:
message (string): Original message
signature (string): Signature as base64 string
Returns: Promise<boolean> - True if signature is valid
Example:
Note: The verify method is available on WalletAccountReadOnlyBtc and is inherited by WalletAccountBtc.
toReadOnlyAccount()
Creates a read-only version of this account that can query balances but cannot sign transactions.
Returns: Promise<WalletAccountReadOnlyBtc> - The read-only account
Example:
dispose()
Disposes the wallet account, securely erasing the private key from memory and closing the Electrum connection.
Returns: void
Example:
Note: getTokenBalance(), transfer(), and quoteTransfer() methods are not supported on the Bitcoin blockchain and will throw errors.
Properties
| Property | Type | Description |
|---|
index | number | The derivation path's index of this account |
path | string | The full derivation path of this account |
keyPair | object | The account's key pair (⚠️ Contains sensitive data) |
⚠️ Security Note: The keyPair property contains sensitive cryptographic material. Never log, display, or expose the private key.
WalletAccountReadOnlyBtc
Represents a read-only Bitcoin wallet account. Extends WalletAccountReadOnly from @tetherto/wdk-wallet.
Constructor
Parameters:
address (string): The account's Bitcoin address
config (BtcWalletConfig, optional): Configuration object (see WalletManagerBtc constructor for details)
Methods
| Method | Description | Returns |
|---|
getBalance() | Returns the confirmed account balance in satoshis | Promise<bigint> |
quoteSendTransaction(options) | Estimates the fee for a transaction | Promise<{fee: bigint}> |
getTransactionReceipt(hash) | Returns a transaction's receipt | Promise<BtcTransaction | null> |
getMaxSpendable() | Returns the maximum spendable amount | Promise<{amount: bigint, fee: bigint, changeValue: bigint}> |
🌐 Supported Networks
This package works with Bitcoin networks:
- Bitcoin Mainnet (
"bitcoin")
- Bitcoin Testnet (
"testnet")
- Bitcoin Regtest (
"regtest")
Electrum Server Configuration
Important: While the package defaults to electrum.blockstream.info:50001 for convenience, we strongly recommend configuring your own Electrum server for production use.
Recommended Approach:
For Production:
- Set up your own Fulcrum server for optimal performance and reliability
- Use recent Fulcrum versions that support pagination for high-transaction addresses
For Development/Testing:
fulcrum.frznode.com:50001 - Generally faster than default
electrum.blockstream.info:50001 - Default fallback
Performance Note: Public Electrum servers may be 10-300x slower and can fail for addresses with many transactions. Always use your own infrastructure for production applications.
Supported Address Types
This implementation supports the following address types:
-
Native SegWit (P2WPKH) (default, BIP-84): Addresses starting with 'bc1' (mainnet) or 'tb1' (testnet)
- Uses BIP-84 derivation paths (
m/84'/0'/account'/0/index for mainnet)
- Lower transaction fees compared to legacy formats
- Full SegWit benefits including transaction malleability protection
-
Legacy (P2PKH) (BIP-44): Addresses starting with '1' (mainnet) or 'm'/'n' (testnet)
- Uses BIP-44 derivation paths (
m/44'/0'/account'/0/index for mainnet)
- Enable via
{ bip: 44 } in config
🔒 Security Considerations
- Seed Phrase Security: Always store your seed phrase securely and never share it
- Private Key Management: The package handles private keys internally with memory safety features
- Network Security: Use trusted Electrum servers or run your own for production
- Transaction Validation: Always verify recipient addresses before sending
- Memory Cleanup: Use the
dispose() method to clear private keys from memory when done
- UTXO Management: UTXO selection and change handling is managed automatically by the wallet
- Fee Management: Fee rates are fetched from mempool.space API automatically
- Address Format: Native SegWit (bech32) addresses are used by default
🛠️ Development
Building
Testing
📜 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🆘 Support
For support, please open an issue on the GitHub repository.