Skip to main content

Overview

This guide shows you how to work with imported Bitcoin wallets for common operations. Once you’ve imported a private key, you can perform various wallet operations directly.

Prerequisites

Step 1: Check Wallet Balance

Check the Bitcoin balance of your imported wallet using a block explorer API:
const address = 'bc1q...your-imported-wallet-address';

// Using Blockstream API
const response = await fetch(
  `https://blockstream.info/api/address/${address}`
);
const data = await response.json();

const balanceSats = data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum;
const balanceBtc = balanceSats / 100_000_000;

console.log('Balance:', balanceSats, 'satoshis');
console.log('Balance in BTC:', balanceBtc);

Step 2: Get UTXOs for Your Wallet

Before sending transactions, you need to fetch available UTXOs:
const address = 'bc1q...your-imported-wallet-address';

// Fetch UTXOs using Blockstream API
const response = await fetch(
  `https://blockstream.info/api/address/${address}/utxo`
);
const utxos = await response.json();

console.log('Available UTXOs:', utxos);
// Output: [{ txid: '...', vout: 0, value: 50000, status: {...} }, ...]

Step 3: Sign Transactions with Imported Wallet

Use your imported wallet to sign Bitcoin transactions:
import * as bitcoin from 'bitcoinjs-lib';
import { BitcoinNetwork } from '@dynamic-labs-wallet/core';

const btcClient = await authenticatedBtcClient();
const walletAddress = 'bc1q...your-imported-wallet-address';

// Create PSBT with your UTXO
const psbt = new bitcoin.Psbt({ network: bitcoin.networks.bitcoin });

// Add input from your wallet
psbt.addInput({
  hash: 'previous_txid',
  index: 0,
  witnessUtxo: {
    script: bitcoin.address.toOutputScript(walletAddress, bitcoin.networks.bitcoin),
    value: 50000, // satoshis
  },
});

// Add output
psbt.addOutput({
  address: 'bc1q...recipient-address',
  value: 40000, // satoshis (minus fee)
});

// Sign with imported wallet
const signedPsbt = await btcClient.signTransaction({
  transaction: psbt.toBase64(),
  senderAddress: walletAddress,
  network: BitcoinNetwork.MAINNET,
});

console.log('Signed PSBT (base64):', signedPsbt);

Step 4: Sign Messages with Imported Wallet

Sign messages for authentication or data integrity:
import { BitcoinNetwork } from '@dynamic-labs-wallet/core';

const message = 'Hello from my imported Bitcoin wallet!';
const signature = await btcClient.signMessage({
  message,
  accountAddress: 'bc1q...your-imported-wallet-address',
  network: BitcoinNetwork.MAINNET,
});

// Returns BIP-322 signature in base64 format
console.log('Message signed (base64):', signature);

Complete Example: Sign and Send from Imported Wallet

import * as bitcoin from 'bitcoinjs-lib';
import { BitcoinNetwork } from '@dynamic-labs-wallet/core';

export const signAndSendFromImportedWallet = async ({
  walletAddress,
  recipientAddress,
  amountSats,
  feeSats,
}: {
  walletAddress: string;
  recipientAddress: string;
  amountSats: number;
  feeSats: number;
}) => {
  const btcClient = await authenticatedBtcClient();
  const network = bitcoin.networks.bitcoin;

  // Step 1: Fetch UTXOs
  const utxoResponse = await fetch(
    `https://blockstream.info/api/address/${walletAddress}/utxo`
  );
  const utxos = await utxoResponse.json();

  if (utxos.length === 0) {
    throw new Error('No UTXOs available');
  }

  // Step 2: Select UTXOs (simple selection - use first one)
  const utxo = utxos[0];

  // Step 3: Create PSBT
  const psbt = new bitcoin.Psbt({ network });

  psbt.addInput({
    hash: utxo.txid,
    index: utxo.vout,
    witnessUtxo: {
      script: bitcoin.address.toOutputScript(walletAddress, network),
      value: utxo.value,
    },
  });

  // Add recipient output
  psbt.addOutput({
    address: recipientAddress,
    value: amountSats,
  });

  // Add change output if needed
  const change = utxo.value - amountSats - feeSats;
  if (change > 546) { // Dust threshold
    psbt.addOutput({
      address: walletAddress,
      value: change,
    });
  }

  // Step 4: Sign
  const signedPsbtBase64 = await btcClient.signTransaction({
    transaction: psbt.toBase64(),
    senderAddress: walletAddress,
    network: BitcoinNetwork.MAINNET,
  });

  // Step 5: Finalize and extract
  const signedPsbt = bitcoin.Psbt.fromBase64(signedPsbtBase64);
  signedPsbt.finalizeAllInputs();
  const rawTx = signedPsbt.extractTransaction().toHex();

  // Step 6: Broadcast
  const broadcastResponse = await fetch('https://blockstream.info/api/tx', {
    method: 'POST',
    body: rawTx,
  });

  const txid = await broadcastResponse.text();
  console.log('Transaction broadcasted:', txid);
  return txid;
};

List All Bitcoin Wallets

Get all Bitcoin wallets associated with your account:
const btcWallets = await btcClient.getBitcoinWallets();

console.log('Bitcoin wallets:', btcWallets.length);
btcWallets.forEach(wallet => {
  console.log(`- ${wallet.accountAddress} (${wallet.chainName})`);
});

Best Practices

  1. Balance Checking: Verify sufficient balance before sending transactions
  2. UTXO Management: Select UTXOs efficiently to minimize fees
  3. Fee Estimation: Use current fee rates from mempool APIs
  4. Error Handling: Implement proper error handling for all wallet operations
  5. Security: Never expose sensitive information in server-side code
  6. Network Selection: Use testnet for development and testing

Fee Estimation

Estimate appropriate fees before sending:
// Fetch recommended fee rates
const feeResponse = await fetch('https://blockstream.info/api/fee-estimates');
const feeEstimates = await feeResponse.json();

// feeEstimates contains sat/vB for different confirmation targets
// e.g., { "1": 25, "3": 15, "6": 10 } means:
// - 25 sat/vB for ~1 block confirmation
// - 15 sat/vB for ~3 block confirmation
// - 10 sat/vB for ~6 block confirmation

// For Native SegWit P2WPKH: ~110 vBytes for 1-in-1-out tx
const estimatedFee = feeEstimates["3"] * 110; // sat for ~3 block confirmation

Next Steps