Skip to main content

Overview

This comprehensive example demonstrates all available functions in the Dynamic BTC SDK, showing the actual API usage patterns and how to handle common operations.
The SDK currently supports Bitcoin Mainnet only. Testnet support is planned for a future release.

Complete Example Code

// Import statements
import { DynamicBtcWalletClient } from "@dynamic-labs-wallet/node-btc";
import { ThresholdSignatureScheme } from "@dynamic-labs-wallet/node";
import { BitcoinAddressType } from "@dynamic-labs-wallet/core";
import * as bitcoin from "bitcoinjs-lib";
import fs from "fs";

// Initialize BTC client
export const authenticatedBtcClient = async () => {
  const client = new DynamicBtcWalletClient({
    environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
  });

  await client.authenticateApiToken(process.env.DYNAMIC_AUTH_TOKEN!);
  return client;
};

// Example usage demonstrating all available functions
async function main() {
  try {
    console.log("Starting BTC Client Demo...\n");

    // Initialize the BTC client
    const btcClient = await authenticatedBtcClient();
    console.log("BTC client authenticated successfully\n");

    // 1. Create a new Native SegWit Bitcoin wallet
    console.log("Creating new Native SegWit wallet...");
    const segwitWallet = await btcClient.createWalletAccount({
      thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
      onError: (error: Error) => {
        console.error("Native SegWit wallet creation error:", error);
      },
      backUpToClientShareService: true,
      bitcoinConfig: {
        addressType: BitcoinAddressType.NATIVE_SEGWIT,
      },
    });

    console.log("Native SegWit wallet created:", segwitWallet.accountAddress);
    console.log("Public key hex:", segwitWallet.publicKeyHex);

    // Save wallet info to file
    fs.writeFileSync("btcWallet.json", JSON.stringify(segwitWallet, null, 2));
    console.log("Wallet saved to btcWallet.json\n");

    // 2. Create a Taproot wallet
    console.log("Creating Taproot wallet...");
    const taprootWallet = await btcClient.createWalletAccount({
      thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
      onError: (error: Error) => {
        console.error("Taproot wallet creation error:", error);
      },
      backUpToClientShareService: true,
      bitcoinConfig: {
        addressType: BitcoinAddressType.TAPROOT,
      },
    });

    console.log("Taproot wallet created:", taprootWallet.accountAddress);

    // 3. Derive address from public key
    console.log("\nDeriving BTC address from public key...");
    try {
      const { accountAddress } = btcClient.deriveAccountAddress({
        rawPublicKey: segwitWallet.rawPublicKey,
        addressType: BitcoinAddressType.NATIVE_SEGWIT,
      });
      console.log("Derived address:", accountAddress);
    } catch (error) {
      console.log("Could not derive address:", error);
    }

    // 4. Get all Bitcoin wallets
    console.log("\nGetting all Bitcoin wallets...");
    try {
      const allWallets = await btcClient.getBitcoinWallets();
      console.log("Found", allWallets.length, "Bitcoin wallets");
      allWallets.forEach(wallet => {
        console.log(`  - ${wallet.accountAddress}`);
      });
    } catch (error) {
      console.log("Could not retrieve all wallets:", error);
    }

    // 5. Sign a message (BIP-322)
    console.log("\nSigning a message with BIP-322...");
    try {
      const message = "Hello, Bitcoin! This is a test message from Dynamic BTC wallet.";
      const signature = await btcClient.signMessage({
        message,
        accountAddress: segwitWallet.accountAddress,
        network: BitcoinNetwork.MAINNET,
      });
      console.log("Message signed successfully (BIP-322)");
      console.log("Signature (base64):", signature.substring(0, 50) + "...");
    } catch (error) {
      console.log("Message signing failed:", error instanceof Error ? error.message : String(error));
    }

    // 6. Sign a message with Taproot wallet
    console.log("\nSigning a message with Taproot wallet...");
    try {
      const message = "Taproot signature test";
      const signature = await btcClient.signMessage({
        message,
        accountAddress: taprootWallet.accountAddress,
        network: BitcoinNetwork.MAINNET,
      });
      console.log("Taproot message signed successfully");
      console.log("Signature (base64):", signature.substring(0, 50) + "...");
    } catch (error) {
      console.log("Taproot message signing failed:", error instanceof Error ? error.message : String(error));
    }

    // 7. Create and sign a PSBT (example transaction)
    console.log("\nPreparing PSBT for signing...");
    try {
      const network = bitcoin.networks.bitcoin;
      const psbt = new bitcoin.Psbt({ network });

      // Example input (you would use real UTXO data in production)
      // This is just to demonstrate the API - it won't broadcast
      const exampleInput = {
        hash: "0000000000000000000000000000000000000000000000000000000000000000",
        index: 0,
        witnessUtxo: {
          script: bitcoin.address.toOutputScript(segwitWallet.accountAddress, network),
          value: 50000,
        },
      };

      psbt.addInput(exampleInput);
      psbt.addOutput({
        address: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", // Example address
        value: 40000,
      });

      console.log("PSBT created, signing...");

      const signedPsbt = await btcClient.signTransaction({
        transaction: psbt.toBase64(),
        senderAddress: segwitWallet.accountAddress,
        network: BitcoinNetwork.MAINNET,
      });

      console.log("PSBT signed successfully");
      console.log("Signed PSBT (base64):", signedPsbt.substring(0, 50) + "...");
    } catch (error) {
      console.log("Transaction signing skipped (no real UTXO):", error instanceof Error ? error.message : String(error));
    }

    // 8. Export private key (WIF format)
    console.log("\nExporting private key...");
    try {
      const wifPrivateKey = await btcClient.exportPrivateKey({
        accountAddress: segwitWallet.accountAddress,
      });
      console.log("Private key exported (WIF format)");
      console.log("WIF:", wifPrivateKey.substring(0, 10) + "...");
    } catch (error) {
      console.log("Private key export not available:", error instanceof Error ? error.message : String(error));
    }

    // 9. Offline export private key from key shares
    console.log("\nOffline exporting private key...");
    try {
      if (segwitWallet.externalServerKeyShares) {
        const wifPrivateKey = await btcClient.offlineExportPrivateKey({
          keyShares: segwitWallet.externalServerKeyShares as any,
          bitcoinConfig: {
            addressType: BitcoinAddressType.NATIVE_SEGWIT,
          },
        });
        console.log("Private key exported offline (WIF):", wifPrivateKey.substring(0, 10) + "...");
      }
    } catch (error) {
      console.log("Offline export not available:", error instanceof Error ? error.message : String(error));
    }

    // 10. Test connection to Bitcoin network (check balance)
    console.log("\nTesting Bitcoin network connection...");
    try {
      const response = await fetch(
        `https://blockstream.info/api/address/${segwitWallet.accountAddress}`
      );
      const data = await response.json();
      const balanceSats = data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum;
      console.log("Bitcoin network connection successful");
      console.log("Wallet balance:", balanceSats, "satoshis");
      console.log("Balance in BTC:", balanceSats / 100_000_000);
    } catch (error) {
      console.log("Bitcoin network connection test skipped");
    }

    // 11. Import private key (if you have one)
    console.log("\nTesting private key import...");
    try {
      const importedWallet = await btcClient.importPrivateKey({
        privateKey: "L1aW4aubDFB7yfras2S1mN3bqg9nwySY8nkoLmJebSLD5BWv3ENZ", // Example WIF
        chainName: "BTC",
        thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
        backUpToClientShareService: true,
        bitcoinConfig: {
          addressType: BitcoinAddressType.NATIVE_SEGWIT,
        },
      });
      console.log("Private key imported:", importedWallet.accountAddress);
    } catch (error) {
      console.log("Private key import skipped (example key)");
    }

    console.log("\nBTC Client Demo completed successfully!");
    console.log("Check btcWallet.json for wallet details");

    // Summary
    console.log("\nDemo Summary:");
    console.log("Successfully completed:");
    console.log(`   - Created Native SegWit wallet: ${segwitWallet.accountAddress}`);
    console.log(`   - Created Taproot wallet: ${taprootWallet.accountAddress}`);
    console.log(`   - Public key hex: ${segwitWallet.publicKeyHex}`);
    console.log(`   - Bitcoin network connection: Working`);

  } catch (error) {
    console.error("Error in BTC demo:", error);
  }
}

// Run the example
main();

Key API Patterns

1. Wallet Creation

const wallet = await btcClient.createWalletAccount({
  thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
  onError: (error: Error) => {
    console.error("Wallet creation error:", error);
  },
  backUpToClientShareService: true,
  bitcoinConfig: {
    addressType: BitcoinAddressType.NATIVE_SEGWIT,
  },
});

2. Message Signing (BIP-322)

const signature = await btcClient.signMessage({
  message: "Hello, Bitcoin!",
  accountAddress: wallet.accountAddress,
  network: BitcoinNetwork.MAINNET,
});
// Returns BIP-322 signature in base64 format

3. Transaction Signing (PSBT)

import * as bitcoin from "bitcoinjs-lib";

const psbt = new bitcoin.Psbt({ network: bitcoin.networks.bitcoin });

psbt.addInput({
  hash: "txid",
  index: 0,
  witnessUtxo: {
    script: bitcoin.address.toOutputScript(wallet.accountAddress, bitcoin.networks.bitcoin),
    value: 50000,
  },
});

psbt.addOutput({
  address: "bc1q...recipient",
  value: 40000,
});

const signedPsbt = await btcClient.signTransaction({
  transaction: psbt.toBase64(),
  senderAddress: wallet.accountAddress,
  network: BitcoinNetwork.MAINNET,
});
// Returns signed PSBT in base64 format

4. Derive Address

// Synchronous - no await needed
const { accountAddress } = btcClient.deriveAccountAddress({
  rawPublicKey: wallet.rawPublicKey,
  addressType: BitcoinAddressType.NATIVE_SEGWIT,
});

5. Get All Wallets

const allWallets = await btcClient.getBitcoinWallets();

6. Export Private Key

const wifPrivateKey = await btcClient.exportPrivateKey({
  accountAddress: wallet.accountAddress,
  password: "your-password", // Only if wallet was created with password
});
// Returns private key in WIF format

Available Functions

The BTC SDK provides the following main functions:
  • createWalletAccount() - Create new Bitcoin wallet
  • importPrivateKey() - Import existing private key (WIF format)
  • getBitcoinWallets() - Get all Bitcoin wallets
  • deriveAccountAddress() - Derive Bitcoin address from a public key
  • signMessage() - Sign messages using BIP-322
  • signTransaction() - Sign PSBTs
  • exportPrivateKey() - Export wallet private key in WIF format
  • offlineExportPrivateKey() - Export private key from key shares offline

Error Handling

Always implement proper error handling:
try {
  const result = await btcClient.someFunction(params);
  console.log("Operation successful:", result);
} catch (error) {
  console.error("Operation failed:", error instanceof Error ? error.message : String(error));
}

Environment Setup

Make sure you have these environment variables:
DYNAMIC_AUTH_TOKEN=your_auth_token_here
DYNAMIC_ENVIRONMENT_ID=your_environment_id_here

Dependencies

Install required packages:
bun add @dynamic-labs-wallet/node-btc @dynamic-labs-wallet/node @dynamic-labs-wallet/core bitcoinjs-lib

Next Steps