bip38-messages
v1.2.0
Published
BIP38 wallet utility for loading encrypted keys and creating Bitcoin transactions with OP_RETURN messages
Maintainers
Readme
BIP38 Messages - Bitcoin Wallet Utility
A command-line utility for loading BIP38 encrypted wallets and creating Bitcoin transactions with OP_RETURN messages. Designed for use with Ballet Real Bitcoin cards and other SegWit wallets.
Features
- ✅ BIP38 Key Decryption - Decrypt encrypted private keys (6P... format)
- ✅ SegWit Support - Native SegWit (P2WPKH) addresses (bc1q... format)
- ✅ OP_RETURN Messages - Embed messages in Bitcoin transactions
- ✅ Automatic UTXO Fetching - No need to manually provide UTXOs!
- ✅ Automatic Broadcasting - Transactions broadcast automatically!
- ✅ Ballet Card Compatible - Works with Ballet Real Bitcoin cards
- ✅ Environment Variables - Secure key management via .env files
- ✅ CLI Interface - Easy-to-use command-line scripts
Installation
npm install
npm run buildQuick Start
1. Set Up Environment Variables (Optional)
Create a .env file:
PRIVATE_KEY=6PnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
PASSPHRASE=your-secret-passphrase2. Load Your Wallet
# Using command-line arguments
npm run wallet:load -- --private-key 6Pn... --passphrase "your-passphrase"
# Using environment variables
npm run wallet:load -- --env-vars PRIVATE_KEY,PASSPHRASE
# Mix of both (env var for key, CLI for passphrase)
npm run wallet:load -- --env-vars PRIVATE_KEY --passphrase "your-passphrase"3. Create and Broadcast a Transaction
That's it! Everything is automatic - UTXOs fetched, transaction signed and broadcast! 🎉
# Send BTC with a message (auto-fetched UTXOs + auto-broadcast!)
npm run wallet:transact -- --to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh --amount 0.0001 --message "Hello Bitcoin" --env-vars PRIVATE_KEY,PASSPHRASE
# Message-only transaction (amount defaults to 0)
npm run wallet:transact -- --to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh --message "Storage test" --env-vars PRIVATE_KEY,PASSPHRASE
# Sign only (don't broadcast) - for manual review
npm run wallet:transact -- --to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh --amount 0.0001 --sign-only --env-vars PRIVATE_KEY,PASSPHRASEThe tool will automatically:
- Query the blockchain for your UTXOs
- Show your balance
- Select optimal UTXOs for the transaction
- Create and sign the transaction
- Broadcast to the network (unless
--sign-onlyis used) - Display the transaction ID and explorer link
Commands
wallet:load
Loads a BIP38 encrypted wallet and displays the address.
Usage:
npm run wallet:load -- [options]Options:
-k, --private-key <key>- BIP38 encrypted private key (starts with 6P)-p, --passphrase <passphrase>- Passphrase to decrypt the BIP38 key (optional)-e, --env-vars <vars>- Environment variable names (comma-separated, up to 2)-n, --network <network>- Bitcoin network:mainnetortestnet(default:mainnet)-h, --help- Display help
Examples:
# Load from command-line
npm run wallet:load -- --private-key 6PnXXX... --passphrase "secret"
# Load from environment variables
npm run wallet:load -- --env-vars PRIVATE_KEY,PASSPHRASE
# Load from environment, override passphrase
npm run wallet:load -- --env-vars PRIVATE_KEY --passphrase "different-secret"
# Testnet wallet
npm run wallet:load -- --private-key 6PnXXX... --passphrase "secret" --network testnetOutput:
✅ Wallet loaded successfully!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Address: bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
🔑 Public Key: 02a1b2c3d4...
🌐 Network: mainnet
💳 Type: P2WPKH (Native SegWit)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━wallet:transact
Creates a Bitcoin transaction with optional OP_RETURN message.
Usage:
npm run wallet:transact -- [options]Options:
-t, --to <address>- Required - Recipient Bitcoin address (bc1q...)-a, --amount <amount>- Amount to send in BTC (default:0)-m, --message <message>- Message to store using OP_RETURN (max 80 bytes)-k, --private-key <key>- BIP38 encrypted private key (starts with 6P)-p, --passphrase <passphrase>- Passphrase to decrypt the BIP38 key-e, --env-vars <vars>- Environment variable names (comma-separated, up to 2)-n, --network <network>- Bitcoin network:mainnetortestnet(default:mainnet)--utxos <utxos>- JSON string of UTXOs to spend (optional - auto-fetched if not provided)-s, --sign-only- Only sign transaction without broadcasting (output hex for manual broadcast)-h, --help- Display help
Note:
- UTXOs are automatically fetched from the blockchain!
- Transactions are automatically broadcast unless
--sign-onlyis used!
Examples:
# Send BTC with message
npm run wallet:transact -- \
--to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh \
--amount 0.0001 \
--message "This will be stored using OP_RETURN" \
--env-vars PRIVATE_KEY,PASSPHRASE
# Message-only transaction
npm run wallet:transact -- \
--to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh \
--message "Storage only" \
--private-key 6PnXXX... \
--passphrase "secret"
# Send BTC without message
npm run wallet:transact -- \
--to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh \
--amount 0.00005 \
--env-vars PRIVATE_KEY,PASSPHRASE
# With UTXOs for broadcasting
npm run wallet:transact -- \
--to bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh \
--amount 0.0001 \
--message "Hello" \
--env-vars PRIVATE_KEY,PASSPHRASE \
--utxos '[{"txid":"abc123...","vout":0,"value":100000}]'UTXO Format:
[
{
"txid": "transaction_id_here",
"vout": 0,
"value": 100000
}
]Where:
txid- Transaction ID of the unspent outputvout- Output index (usually 0 or 1)value- Amount in satoshis (100,000 satoshis = 0.001 BTC)
Output (with auto-broadcast):
🔐 Preparing transaction...
✅ Wallet loaded
📍 From: bc1q...
📍 To: bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
💰 Amount: 0.0001 BTC
💬 Message: This will be stored using OP_RETURN
📡 Broadcasting transaction to network...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Transaction broadcast successfully!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📄 Transaction ID (TXID):
abc123def456...
🔗 View on Blockstream:
https://blockstream.info/tx/abc123def456...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 Transaction is now in the mempool
It will be confirmed in the next block
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Output (with --sign-only):
🔐 Preparing transaction...
✅ Wallet loaded
📍 From: bc1q...
📍 To: bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
💰 Amount: 0.0001 BTC
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Transaction created and signed!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📄 Signed Transaction Hex:
0200000001...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 Sign-only mode: Transaction not broadcast
To broadcast manually:
1. bitcoin-cli sendrawtransaction <hex>
2. Or visit: https://blockstream.info/tx/push
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Automatic UTXO Fetching
Good news! UTXOs are now automatically fetched from the blockchain when you create a transaction. You don't need to manually provide them anymore!
The tool will:
- ✅ Automatically query Blockstream API for your address
- ✅ Select optimal UTXOs for your transaction
- ✅ Display your balance before creating the transaction
- ✅ Handle both mainnet and testnet
Manual UTXO Provision (Optional)
If you want to manually specify which UTXOs to use, you still can:
Using Bitcoin CLI:
bitcoin-cli listunspent 1 9999999 '["bc1qYOUR_ADDRESS_HERE"]'Using Block Explorers:
- Blockstream (Mainnet): https://blockstream.info/address/YOUR_ADDRESS
- Blockstream (Testnet): https://blockstream.info/testnet/address/YOUR_ADDRESS
Using APIs:
# Blockstream API (Mainnet)
curl https://blockstream.info/api/address/bc1qYOUR_ADDRESS/utxo
# Blockstream API (Testnet)
curl https://blockstream.info/testnet/api/address/YOUR_ADDRESS/utxoEnvironment Variables
The utility supports loading keys and passphrases from environment variables for security.
Setting Up .env:
# Your BIP38 encrypted private key (starts with 6P)
PRIVATE_KEY=6PnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Your passphrase for decrypting the BIP38 key
PASSPHRASE=your-secret-passphrase-hereUsing Environment Variables:
The --env-vars flag accepts up to 2 comma-separated variable names:
- First variable: Private key (required)
- Second variable: Passphrase (optional)
# Both from environment
npm run wallet:load -- --env-vars PRIVATE_KEY,PASSPHRASE
# Only private key from environment
npm run wallet:load -- --env-vars PRIVATE_KEY --passphrase "cli-passphrase"
# Custom variable names
npm run wallet:load -- --env-vars MY_KEY,MY_PASSBallet Real Bitcoin Cards
This utility is designed to work with Ballet Real Bitcoin physical cryptocurrency cards. These cards use:
- BIP38 Encryption - Private keys are encrypted with a passphrase
- SegWit Addresses - Native SegWit (P2WPKH) format (bc1q...)
- Physical Security - Cards have tamper-evident stickers
How to Use with Ballet Cards:
- Find Your Encrypted Key - Scratch off the passphrase panel and private key panel
- Load the Wallet - The private key starts with
6P... - Decrypt - Use the passphrase from the card
- Transact - Create transactions using the loaded wallet
npm run wallet:load -- --private-key 6Pn... --passphrase "062T-..."Technical Details
Address Types
This utility generates P2WPKH (Pay to Witness Public Key Hash) addresses:
- Format:
bc1q...(mainnet) ortb1q...(testnet) - Type: Native SegWit
- Benefits: Lower fees, better privacy, increased security
OP_RETURN Messages
OP_RETURN is a Bitcoin script opcode used to store data on the blockchain:
- Maximum size: ~80 bytes
- Non-spendable output (data only)
- Use cases: Timestamping, proof of existence, short messages
Transaction Structure
Inputs: UTXOs from your address
Outputs:
- Recipient output (if amount > 0)
- OP_RETURN output (if message provided)
- Change output (back to your address)Security Notes
⚠️ Important Security Considerations:
- Never share your private key or passphrase
- Use environment variables for sensitive data, not command-line arguments
- The .env file should never be committed to version control (already in .gitignore)
- Test with small amounts first on testnet
- Verify addresses before sending real BTC
- This tool does NOT broadcast transactions - you must do that separately
Development
Project Structure
bip38-messages/
├── src/
│ ├── lib/
│ │ └── wallet.ts # Core wallet functions
│ ├── cli/
│ │ ├── wallet-load.ts # Load wallet command
│ │ └── wallet-transact.ts # Transaction command
├── dist/ # Compiled JavaScript
├── package.json
├── tsconfig.json
└── README.mdBuilding
npm run buildRunning with tsx (Development)
npx tsx src/cli/wallet-load.ts --help
npx tsx src/cli/wallet-transact.ts --helpTroubleshooting
"Passphrase required for encrypted BIP38 keys"
- Ensure you provide a passphrase for encrypted keys (starting with 6P)
- Use
--passphraseflag or second env var in--env-vars
"Invalid private key format"
- Check that your key starts with
6Pfor BIP38 - Or provide a valid WIF format key
"No UTXOs provided"
- You need to query your address for unspent outputs
- Use Bitcoin CLI or block explorer APIs
- Provide UTXOs using
--utxosflag
"Message too long"
- OP_RETURN messages are limited to ~80 bytes
- Keep your messages short
Future Enhancements
- [ ] Support for additional address types (P2PKH, P2SH-P2WPKH)
- [ ] Built-in UTXO fetching from block explorers
- [ ] Automatic transaction broadcasting
- [ ] Multi-signature support
- [ ] Hardware wallet integration
- [ ] QR code generation for addresses
License
MIT
Disclaimer
This software is provided "as is", without warranty of any kind. Use at your own risk. Always test with small amounts first.
