btc-bridge-lib-temp
v0.3.1
Published
Bitcoin Bridge Library for handling multi-signature wallet operations, deposits, and withdrawals
Maintainers
Readme
ZenBridge Bitcoin Lib
A production-ready Bitcoin-to-Ethereum bridge system with enterprise-grade security, multi-signature wallet management, and cross-chain interoperability.
Bitcoin Lab implements a sophisticated bridge protocol using PSBT (Partially Signed Bitcoin Transactions), 3-of-5 multi-signature wallets, and CCIM (Cross-Chain Interoperability Message) for secure Bitcoin-Ethereum transfers.
Overview
Key Components
- Observer Service: Central coordinator that monitors Bitcoin via Esplora and Zenchain via Subquery, indexes data to PostgreSQL, broadcasts transactions to Bitcoin network
- Operator Nodes: Independent PSBT signers that connect directly to PostgreSQL, read unsigned PSBTs, write signatures, broadcast to Zenchain network via bridge operator nodes
- PostgreSQL Database: Central state management where operators read unsigned PSBTs and write signatures, Observer reads/writes transaction state data
- Multi-Signature Wallets: 3-of-5 threshold signatures using PSBT coordination
- Subquery Indexer: Indexes Zenchain bridge contract events for withdrawal processing
- Bridge Contracts: Zenchain smart contracts that emit events for cross-chain transfers
- No Inter-Service Communication: Services only communicate through the shared PostgreSQL database
Quick Start
Prerequisites
- Docker and Docker Compose
- Node.js 18+ (for development)
Development Setup
Clone the repository
git clone https://github.com/your-org/bitcoin-lab.git cd bitcoin-labStart the development environment
# Start all services (PostgreSQL, Esplora, Observer, 5 Operators) docker-compose -f docker-compose.dev.yaml up -d # Check service health docker-compose -f docker-compose.dev.yaml psSet up environment variables
# Copy environment template cp .env.example .env # Edit with your configuration DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres ESPLORA_URL=http://localhost/regtest/api NETWORK=regtestVerify setup
# Check observer status docker logs btc_observer_dev # Check operator status docker logs btc_operator_1_dev
Build from Source
Prerequisites
- Node.js 20+
- npm or yarn package manager
- PostgreSQL database
- Docker (for development environment)
Installation
# Clone the repository
git clone https://github.com/zenchain-protocol/zenbridge-btc-lib.git
cd zenbridge-btc-lib
# Install dependencies
npm installBuild Process
# Build TypeScript to JavaScript
npm run build
# Run tests
npm test
# Run CLI
npm run cli
# Development mode (with hot reload)
npm run devBuild Outputs
dist/- Compiled JavaScript and type definitionsdist/cli/run.js- CLI executabledist/index.js- Main library entry point
CLI Reference
The btc-bridge-cli provides comprehensive management capabilities for the Bitcoin bridge system:
Global Options
-V, --version # Show version number
-v, --verbose # Enable verbose logging (debug level)
-q, --quiet # Enable quiet logging (error level only)
--log-level <level> # Set log level (trace, debug, info, warn, error, fatal)
--database-url <url> # PostgreSQL connection string (overrides env vars)
-h, --help # Show command helpDatabase Management
# Migration commands
btc-bridge-cli migrate up # Run pending migrations
btc-bridge-cli migrate down <version> # Rollback to specific migration version
btc-bridge-cli migrate version # Show current migration version
# Configuration
btc-bridge-cli init [options] # Initialize operator configurations
btc-bridge-cli populate <configPath> # Populate database with public configMigration Options
btc-bridge-cli migrate up # Apply all pending migrations
btc-bridge-cli migrate down 003 # Rollback to migration version 003
btc-bridge-cli migrate version # Check current database migration statusInitialization Options
btc-bridge-cli init \
--network <network> # Bitcoin network (mainnet, testnet, regtest)
--operators <count> # Number of operators (default: 5)
--threshold <threshold> # Signature threshold (default: 3)
--refund-lock-time <seconds> # Refund locktime in seconds (default: 172800)
--block-confirmations <blocks> # Confirmation requirement (default: 6)
--output-dir <dir> # Config output directory (default: ./configs)Service Operations
# Observer Service (monitors both networks)
btc-bridge-cli observe [subcommand] # Run observer services
btc-bridge-cli observe all # Run all observer services
btc-bridge-cli observe wallet # Wallet monitoring only
btc-bridge-cli observe psbt # PSBT processing only
btc-bridge-cli observe ccim # CCIM message processing only
# Operator Service (PSBT signers)
btc-bridge-cli operate <operatorId> # Run operator service (ID 1-5)Observer Options
btc-bridge-cli observe all \
--delay <ms> # Cycle delay in milliseconds (default: 5000)
--esplora <url> # Esplora API URL override
--network <network> # Bitcoin network (default: regtest)
--cycles <number> # Limited cycle count (default: infinite)
--subquery-url <url> # SubQuery GraphQL endpoint URLOperator Options
btc-bridge-cli operate 1 \
--delay <ms> # Cycle delay in milliseconds (default: 3000)
--network <network> # Bitcoin network (default: regtest)
--mnemonic <phrase> # BIP39 seed phrase (or OPERATOR_MNEMONIC env var)
--cycles <number> # Limited cycle count (default: infinite)Wallet Management
# Create wallets
btc-bridge-cli create deposit <count> # Create deposit wallets
btc-bridge-cli create hodl <count> # Create HODL walletsWithdrawal Processing
# Mock withdrawal for testing
btc-bridge-cli withdraw <ethAddress> <btcAddress> <amountBTC> \
--esplora <url> # Esplora API URL
--network <network> # Bitcoin network
--config <path> # Public config file path
--fee <btc> # Transaction fee in BTC (default: 0.0001)Complete Setup Examples
# 1. Database setup and configuration
btc-bridge-cli migrate up
btc-bridge-cli init --network regtest --operators 5 --threshold 3
btc-bridge-cli populate ./configs/public-config.json
# 2. Create wallet infrastructure
btc-bridge-cli create deposit 10
btc-bridge-cli create hodl 5
# 3. Start observer service (single process)
btc-bridge-cli observe all --verbose --delay 5000 &
# 4. Start multiple operators (separate processes)
btc-bridge-cli operate 1 --verbose &
btc-bridge-cli operate 2 --verbose &
btc-bridge-cli operate 3 --verbose &
# 5. Test withdrawal
btc-bridge-cli withdraw \
0x742d35Cc6610C7532C8B77D566D77Bd0e5BfD726 \
tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh \
0.001
# 6. Check system status with custom database
btc-bridge-cli --database-url postgresql://user:pass@host:5432/btc_bridge \
migrate versionDevelopment Workflow
# Start with clean database
btc-bridge-cli --database-url $DEV_DATABASE_URL migrate up
# Generate development configuration
btc-bridge-cli init \
--network regtest \
--output-dir ./dev-configs \
--refund-lock-time 3600
# Set up development environment
btc-bridge-cli populate ./dev-configs/public-config.json
btc-bridge-cli create deposit 20
btc-bridge-cli create hodl 10
# Run services in development mode
btc-bridge-cli observe all --cycles 100 --delay 1000 &
for i in {1..3}; do
btc-bridge-cli operate $i --cycles 100 --delay 1000 &
doneAPI References
The Bitcoin Bridge Library exposes several service classes for programmatic integration. Each service follows consistent initialization patterns and provides specific functionality for bridge operations.
BridgeService
Purpose: Main user-facing API for deposit/withdrawal operations and status queries.
Initialization:
import { BridgeService } from 'btc-bridge-lib';
import { Pool } from 'pg';
// Using factory method (recommended)
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const configManager = new ConfigManager('./configs/public-config.json');
const logger = pino({ level: 'info' });
const bridgeService = await BridgeService.init(pool, configManager, logger);
// Direct constructor
const bridgeService = new BridgeService(
pool,
operatorPublicKeyManagers,
configManager,
logger
);Core Methods:
// Create new deposit address
const deposit = await bridgeService.createDeposit(
'0x742d35Cc6610C7532C8B77D566D77Bd0e5BfD726', // Ethereum receiver
'tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh' // Bitcoin refund address
);
// Query deposit status
const status = await bridgeService.getDepositStatus('deposit-123');
// Query withdrawal status
const withdrawal = await bridgeService.getWithdrawalStatus('0xabc...');
// Get user transaction history
const deposits = await bridgeService.getDepositHistory(
'0x742d35Cc6610C7532C8B77D566D77Bd0e5BfD726',
10, // limit
0 // offset
);
// Rate limiting checks
const canProceed = await bridgeService.canProceed(ethereumAddress);
const rateLimit = await bridgeService.checkRateLimit(ethereumAddress);Constants:
BridgeService.SCHEME // 'p2sh' - default wallet schemeObserverService
Purpose: Central monitoring service that coordinates bridge operations and handles automated workflows.
Initialization:
import { ObserverService } from 'btc-bridge-lib';
const observerService = new ObserverService(
pool, // PostgreSQL connection
esploraClient, // Bitcoin API client
operatorPublicKeyManagers, // Array of operator key managers
zenchainService, // Zenchain blockchain service
subqueryService, // Cross-chain message service
configManager, // Network configuration
logger, // Structured logger
{ batchSize: 10 } // Optional batch processing config
);Workflow Methods:
// Wallet lifecycle management
await observerService.handleDepositWalletsToCreate(); // Generate new deposit addresses
await observerService.handleHodlWalletsToGenerate(); // Create HODL storage wallets
await observerService.handleWalletsToCredit(); // Credit wallets with UTXOs
await observerService.handleWalletsToSweep(); // Sweep deposits to HODL
// Transaction processing
await observerService.handlePsbtSessionsToFinalise(); // Finalize signed PSBTs
await observerService.handlePsbtSessionsToBroadcast(); // Broadcast to Bitcoin network
await observerService.handlePsbtSessionsToConfirm(); // Confirm transaction inclusion
// Cross-chain operations
await observerService.handleCCIMMessagesForWithdrawals(); // Process withdrawal requestsReturn Type: All methods return Promise<ObserverProcessResult>:
interface ObserverProcessResult {
success: boolean;
processed: number;
errors: string[];
}OperatorService
Purpose: Individual operator node for PSBT signing in the multi-signature scheme.
Initialization:
import { OperatorService } from 'btc-bridge-lib';
const operatorService = new OperatorService(
pool, // PostgreSQL connection
operatorKeyManager, // Single operator's private keys
logger, // Structured logger
{ batchSize: 5 } // Optional batch processing config
);Core Methods:
// Main signing workflow
const result = await operatorService.handleSessionsToSign();
// Query operations
const deposits = await operatorService.getConfirmedDeposits(
sweepId, // Specific sweep ID
20, // limit
0 // offset
);
// Operator identification
const id = operatorService.operatorId; // Returns number (1-5)Return Type: Promise<OperatorProcessResult>:
interface OperatorProcessResult {
success: boolean;
signedSessions: number;
skippedSessions: number;
errors: string[];
}ZenchainService
Purpose: Zenchain blockchain integration for cross-chain messaging and contract interactions.
Initialization:
import { ZenchainService, NetworkType } from 'btc-bridge-lib';
// Auto-configuration based on network
const zenchainService = new ZenchainService(
NetworkType.REGTEST, // Network type
'http://localhost:8545' // Optional RPC URL override
);Blockchain Methods:
// Contract information
const operatorVersion = await zenchainService.getCurrentOperatorVersion();
const networkConfig = zenchainService.getNetworkConfig();
const publicClient = zenchainService.getPublicClient();
// Contract addresses
const zbtcAddress = zenchainService.getZBTCAddress();
const bridgeAddress = zenchainService.getBridgeAddress();
const directoryAddress = zenchainService.getBridgeDirectoryAddress();
// Network information
const chainId = zenchainService.getChainId();
const networkType = zenchainService.getNetworkType();
const bitcoinNetwork = zenchainService.getBitcoinNetwork();
// Fee information
const feePerbill = await zenchainService.getBridgeFeePerbill();
// CCIM message creation
const ccimMessage = await zenchainService.getCCIMMessageFromDeposit(
depositAddress,
amount,
ethereumReceiver
);CAIP Utilities:
// Static helper methods for Cross-Chain Asset Identification Protocol
const chainId = ZenchainService.createBitcoinChainId('mainnet');
const accountId = ZenchainService.createBitcoinAccountId('bc1qxy...', 'mainnet');
const assetId = ZenchainService.createBitcoinAssetId('mainnet');Constants:
ZenchainService.PERBILL // BigInt("1000000000") - fee calculation baseSubqueryService
Purpose: GraphQL client for querying indexed blockchain data and CCIM messages.
Initialization:
import { SubqueryService } from 'btc-bridge-lib';
const subqueryService = new SubqueryService(
'https://api.subquery.network/sq/project/ccim-messages', // GraphQL endpoint
logger, // Structured logger
30000 // Request timeout (ms)
);Query Methods:
// Fetch new CCIM transfer messages
const result = await subqueryService.fetchNewCCIMMessages({
first: 10, // Pagination limit
offset: 0, // Pagination offset
orderBy: 'BLOCK_HEIGHT_DESC', // Sort order
filter: { // Optional filters
blockHeight: { greaterThan: 1000000 },
messageType: { equalTo: 'TRANSFER' }
}
});
// Get configured endpoint
const url = subqueryService.getQueryUrl();Return Type: Promise<FetchCCIMMessagesResult>:
interface FetchCCIMMessagesResult {
messages: CCIMMessage[];
totalCount: number;
hasNextPage: boolean;
}Service Integration Example
Complete Bridge Setup:
import {
BridgeService,
ObserverService,
OperatorService,
ZenchainService,
SubqueryService,
ConfigManager
} from 'btc-bridge-lib';
import { Pool } from 'pg';
import pino from 'pino';
// Database connection
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const logger = pino({ level: 'info' });
// Configuration
const configManager = new ConfigManager('./configs/public-config.json');
// External services
const zenchainService = new ZenchainService(NetworkType.REGTEST);
const subqueryService = new SubqueryService(process.env.SUBQUERY_URL!, logger);
// Bridge service for user API
const bridgeService = await BridgeService.init(pool, configManager, logger);
// Observer service for automated workflows
const observerService = new ObserverService(
pool,
esploraClient,
operatorPublicKeyManagers,
zenchainService,
subqueryService,
configManager,
logger.child({ service: 'observer' })
);
// Operator services (one per operator)
const operatorServices = await Promise.all(
Array.from({ length: 5 }, async (_, i) => {
const operatorId = i + 1;
const keyManager = await OperatorKeyManager.load(operatorId, mnemonic);
return new OperatorService(
pool,
keyManager,
logger.child({ service: 'operator', operatorId })
);
})
);
// Service lifecycle
await observerService.handleDepositWalletsToCreate();
await Promise.all(operatorServices.map(service => service.handleSessionsToSign()));Error Handling Pattern:
try {
const result = await observerService.handleWalletsToSweep();
if (!result.success) {
logger.error({ errors: result.errors }, 'Observer processing failed');
}
} catch (error) {
logger.error({ error }, 'Observer service error');
}Contributing
We welcome contributions to the Bitcoin Bridge Library! Please see CONTRIBUTING.md for detailed development workflow, coding standards, and guidelines for:
- Setting up the development environment
- Code style and linting requirements
- Testing procedures
- Pull request guidelines
- Release process
Acknowledgments
- BitcoinJS for Bitcoin transaction handling
- Viem for Ethereum integration
- PostgreSQL for robust data persistence
- Blockstream Esplora for Bitcoin blockchain data
