UNPKG

@btc-stamps/tx-builder

Version:

Transaction builder for Bitcoin Stamps and SRC-20 tokens with advanced UTXO selection

785 lines (773 loc) 23.2 kB
import { Network } from 'bitcoinjs-lib'; import { I as IUTXOProvider, P as ProviderOptions, U as UTXO, B as Balance, T as Transaction, A as AddressHistoryOptions, a as AddressHistory, E as ElectrumXOptions } from './provider.interface-53Rg30ZJ.js'; import { F as FeeSource, N as NormalizedFeeRate } from './fee-normalizer-BGRDTCVR.js'; /** * Base UTXO Provider * Common functionality for all provider implementations * Includes fee normalization for consistency with BTCStampsExplorer */ declare abstract class BaseProvider implements IUTXOProvider { protected network: Network; protected timeout: number; protected retries: number; protected retryDelay: number; protected maxRetryDelay: number; constructor(options: ProviderOptions); abstract getUTXOs(address: string): Promise<UTXO[]>; abstract getBalance(address: string): Promise<Balance>; abstract getTransaction(txid: string): Promise<Transaction>; abstract broadcastTransaction(hexTx: string): Promise<string>; abstract getFeeRate(priority?: 'low' | 'medium' | 'high'): Promise<number>; abstract getBlockHeight(): Promise<number>; abstract isConnected(): Promise<boolean>; abstract getAddressHistory(address: string, options?: AddressHistoryOptions): Promise<AddressHistory[]>; getNetwork(): Network; /** * Execute request with retry logic */ protected executeWithRetry<T>(fn: () => Promise<T>, retries?: number): Promise<T>; /** * Execute request with timeout */ protected executeWithTimeout<T>(fn: () => Promise<T>, timeout?: number): Promise<T>; /** * Sleep for specified milliseconds */ protected sleep(ms: number): Promise<void>; /** * Validate Bitcoin address format */ protected isValidAddress(address: string): boolean; /** * Validate transaction ID format */ protected isValidTxid(txid: string): boolean; /** * Convert satoshis to BTC */ protected satoshisToBTC(satoshis: number): number; /** * Convert BTC to satoshis */ protected btcToSatoshis(btc: number): number; /** * Normalize fee rate from provider response to consistent satsPerVB */ protected normalizeFeeRate(rate: any, source: FeeSource): NormalizedFeeRate | null; /** * Get normalized fee rate ensuring it's within acceptable bounds */ protected getNormalizedFeeRate(priority?: 'low' | 'medium' | 'high'): Promise<NormalizedFeeRate>; /** * Convert legacy fee rate response to normalized format */ protected normalizeLegacyFeeResponse(feeResponse: any, source: FeeSource): NormalizedFeeRate | null; /** * Get the fee source identifier for this provider * Override in child classes to specify the correct source */ protected getProviderSource(): FeeSource; /** * Validate that fee rate is reasonable for the current network conditions */ protected validateFeeRate(satsPerVB: number): boolean; /** * Get all priority levels with normalized rates */ getNormalizedFeeRates(): Promise<{ low: NormalizedFeeRate; medium: NormalizedFeeRate; high: NormalizedFeeRate; urgent?: NormalizedFeeRate; }>; } /** * ElectrumX Configuration for tx-builder * Supports centralized configuration with environment variable support */ interface ElectrumXEndpoint { host: string; port: number; protocol: 'tcp' | 'ssl' | 'ws' | 'wss'; maxRetries?: number; timeout?: number; priority?: number; description?: string; } interface ElectrumXConfig { endpoints: ElectrumXEndpoint[]; network: Network; fallbackToPublic?: boolean; connectionTimeout?: number; requestTimeout?: number; maxRetries?: number; } /** * ElectrumX Provider * Full ElectrumX protocol implementation with WebSocket support */ interface ElectrumXServerInfo { genesis_hash: string; hash_function: string; hosts?: Record<string, any>; protocol_max: string; protocol_min: string; pruning?: number; server_version: string; } interface ElectrumXFeeEstimate { [blocks: number]: number; } /** * ElectrumX provider for interacting with Bitcoin network via ElectrumX servers * * @remarks * ElectrumXProvider implements a robust connection to ElectrumX servers with: * - Automatic server failover and retry logic * - WebSocket connection management * - Full ElectrumX protocol support * - Built-in caching for performance * - Address validation and script hash conversion * * Features: * - Multiple server endpoints with automatic failover * - Configurable retry attempts and timeouts * - UTXO fetching with mempool awareness * - Transaction broadcasting and monitoring * - Balance queries with confirmed/unconfirmed breakdown * - Fee estimation support * * @example * ```typescript * const provider = new ElectrumXProvider({ * endpoints: [ * { host: 'electrum.blockstream.info', port: 50002, ssl: true } * ], * network: networks.bitcoin, * maxRetries: 3 * }); * * const utxos = await provider.getUTXOs('bc1q...'); * const balance = await provider.getBalance('bc1q...'); * ``` */ declare class ElectrumXProvider extends BaseProvider { private config; private currentEndpoint; private failedEndpoints; private ws; private tcpClient; private requestId; private pendingRequests; private connectionPromise; private serverInfo; private isConnecting; private heartbeatTimer; private lastHeartbeat; private heartbeatInterval; private missedHeartbeats; private maxMissedHeartbeats; private reconnectAttempts; private maxReconnectAttempts; private reconnectDelay; constructor(options?: ElectrumXOptions); /** * Get UTXOs for a given address */ getUTXOs(address: string): Promise<UTXO[]>; /** * Get balance for a given address */ getBalance(address: string): Promise<Balance>; /** * Get transaction by ID */ getTransaction(txid: string): Promise<Transaction>; /** * Broadcast a signed transaction */ broadcastTransaction(hexTx: string): Promise<string>; /** * Get comprehensive fee estimates for multiple confirmation targets */ getFeeEstimates(): Promise<ElectrumXFeeEstimate>; /** * Get current fee rate (sat/vB) for specific priority */ getFeeRate(priority?: 'low' | 'medium' | 'high'): Promise<number>; /** * Get current block height */ getBlockHeight(): Promise<number>; /** * Get address transaction history */ getAddressHistory(address: string, options?: AddressHistoryOptions): Promise<AddressHistory[]>; /** * Check if provider is connected */ isConnected(): Promise<boolean>; /** * Convert Bitcoin address to ElectrumX script hash */ private addressToScriptHash; /** * Get script public key for address */ private getScriptPubKey; /** * Ensure WebSocket connection is established */ private ensureConnection; /** * Establish WebSocket connection */ private connect; /** * Connect to a specific endpoint */ private connectToEndpoint; /** * Connect via TCP/SSL */ private connectViaTCP; /** * Connect via WebSocket */ private connectViaWebSocket; /** * Make JSON-RPC call to ElectrumX server */ private call; /** * Handle ElectrumX response */ private handleResponse; /** * Start heartbeat monitoring */ private startHeartbeat; /** * Stop heartbeat monitoring */ private stopHeartbeat; /** * Perform heartbeat check */ private performHeartbeat; /** * Send ping to server */ private sendPing; /** * Schedule automatic reconnection with exponential backoff */ private scheduleReconnection; /** * Cleanup connections and pending requests */ private cleanup; /** * Disconnect from ElectrumX server */ disconnect(): Promise<void>; /** * Get server information */ getServerInfo(): ElectrumXServerInfo | null; /** * Get current configuration */ getConfig(): ElectrumXConfig; /** * Get current active endpoint */ getCurrentEndpoint(): ElectrumXEndpoint | null; /** * Get failed endpoints (for debugging) */ getFailedEndpoints(): string[]; /** * Reset failed endpoints (to allow retry) */ resetFailedEndpoints(): void; /** * Test connection to all configured endpoints */ testEndpoints(): Promise<Array<{ endpoint: ElectrumXEndpoint; success: boolean; error?: string; }>>; } /** * Create ElectrumX provider with default configuration (legacy compatibility) */ declare function createElectrumXProvider(host: string, port: number, network: Network, options?: Partial<ElectrumXOptions>): ElectrumXProvider; /** * Create ElectrumX provider with multiple endpoints */ declare function createMultiEndpointProvider(endpoints: Array<{ host: string; port: number; protocol?: 'tcp' | 'ssl' | 'ws' | 'wss'; priority?: number; }>, network: Network, options?: Partial<ElectrumXOptions>): ElectrumXProvider; /** * Create ElectrumX provider for local development * Reads configuration from environment variables */ declare function createLocalDevelopmentProvider(network?: Network): ElectrumXProvider; /** * Create ElectrumX provider with public endpoints only */ declare function createPublicProvider(network?: Network): ElectrumXProvider; /** * Create ElectrumX provider from environment configuration */ declare function createProviderFromEnvironment(): ElectrumXProvider; /** * ElectrumX Server Performance Monitoring and Metrics * Comprehensive performance tracking, scoring, and monitoring capabilities */ interface ServerMetrics { totalRequests: number; successfulRequests: number; failedRequests: number; averageResponseTime: number; minResponseTime: number; maxResponseTime: number; p50ResponseTime: number; p95ResponseTime: number; p99ResponseTime: number; activeConnections: number; totalConnections: number; connectionFailures: number; consecutiveFailures: number; consecutiveSuccesses: number; lastFailureTime: number; lastSuccessTime: number; uptime: number; circuitBreakerTrips: number; circuitBreakerState: 'closed' | 'open' | 'half-open'; circuitBreakerOpenTime?: number; performanceScore: number; reliabilityScore: number; overallScore: number; firstRequestTime: number; lastRequestTime: number; lastHeartbeatTime: number; } interface PerformanceWindow { windowStart: number; windowEnd: number; requestCount: number; successCount: number; averageResponseTime: number; maxResponseTime: number; minResponseTime: number; } interface ServerPerformanceHistory { serverId: string; windows: PerformanceWindow[]; dailyMetrics: Map<string, ServerMetrics>; hourlyMetrics: Map<string, ServerMetrics>; } interface ElectrumXServer { host: string; port: number; protocol?: 'tcp' | 'ssl' | 'ws' | 'wss'; weight?: number; region?: string; timeout?: number; } interface ConnectionPoolOptions { network: Network; servers: ElectrumXServer[]; maxConnectionsPerServer?: number; minConnectionsPerServer?: number; healthCheckInterval?: number; heartbeatInterval?: number; connectionTimeout?: number; requestTimeout?: number; retries?: number; retryDelay?: number; maxRetryDelay?: number; backoffMultiplier?: number; loadBalanceStrategy?: 'round-robin' | 'weighted' | 'least-connections' | 'health-based'; failoverThreshold?: number; circuitBreakerThreshold?: number; circuitBreakerTimeout?: number; recoveryTimeout?: number; maxPoolSize?: number; enableDynamicScaling?: boolean; } /** * ElectrumX Connection Pool with advanced load balancing and health monitoring */ declare class ElectrumXConnectionPool { private options; private connections; private serverHealth; private performanceMonitor; private currentServerIndex; private healthCheckTimer; private heartbeatTimer; private connectionWaiters; private totalConnectionCount; constructor(options: ConnectionPoolOptions); /** * Get UTXOs using the best available connection */ getUTXOs(address: string): Promise<UTXO[]>; /** * Get balance using the best available connection */ getBalance(address: string): Promise<Balance>; /** * Get transaction using the best available connection */ getTransaction(txid: string): Promise<Transaction>; /** * Broadcast transaction using the best available connection */ broadcastTransaction(hexTx: string): Promise<string>; /** * Get fee rate using the best available connection */ getFeeRate(priority?: 'low' | 'medium' | 'high'): Promise<number>; /** * Get block height using the best available connection */ getBlockHeight(): Promise<number>; /** * Get address transaction history using the best available connection */ getAddressHistory(address: string, options?: AddressHistoryOptions): Promise<AddressHistory[]>; /** * Execute operation with load balancing, circuit breaker, and exponential backoff */ private executeWithLoadBalancing; /** * Create a timeout promise */ private createTimeoutPromise; /** * Get or create a connection to the specified server with improved queueing */ private getOrCreateConnection; /** * Create a new connection to the server */ private createNewConnection; /** * Wait for an available connection using proper queueing */ private waitForAvailableConnection; /** * Remove waiter from queue */ private removeWaiter; /** * Release connection back to pool and notify waiters */ private releaseConnection; /** * Update connection success metrics */ private updateConnectionSuccess; /** * Update connection failure metrics */ private updateConnectionFailure; /** * Select best server based on load balancing strategy */ private selectServer; /** * Round-robin server selection */ private selectRoundRobin; /** * Weighted server selection */ private selectWeighted; /** * Least connections server selection */ private selectLeastConnections; /** * Health-based server selection with enhanced performance metrics */ private selectHealthBased; /** * Get healthy servers (circuit breaker aware) */ private getHealthyServers; /** * Get available servers (includes healthy servers and half-open circuit breakers) */ private getAvailableServers; /** * Check if server is available (healthy or circuit breaker allows test) */ private isServerAvailable; /** * Initialize server health tracking with circuit breaker support */ private initializeServerHealth; /** * Update server health metrics with circuit breaker logic */ private updateServerHealth; /** * Update composite health score (0-100) */ private updateHealthScore; /** * Start periodic health checking */ private startHealthChecking; /** * Start heartbeat monitoring */ private startHeartbeat; /** * Perform health checks on all servers */ private performHealthChecks; /** * Perform heartbeat checks on active connections */ private performHeartbeats; /** * Perform heartbeat on a specific connection */ private performConnectionHeartbeat; /** * Remove a specific connection from the pool */ private removeConnection; /** * Cleanup idle and unhealthy connections */ private cleanupIdleConnections; /** * Adjust pool size based on load and performance */ private adjustPoolSize; /** * Get server key for mapping */ private getServerKey; /** * Sleep for specified milliseconds */ private sleep; /** * Get comprehensive pool statistics */ getStats(): { servers: Array<{ server: string; healthy: boolean; activeConnections: number; totalRequests: number; successRate: number; averageResponseTime: number; consecutiveFailures: number; healthScore: number; circuitBreakerState: string; lastHeartbeat: Date | null; connectionsInUse: number; }>; totalConnections: number; totalActiveConnections: number; averageHealthScore: number; circuitBreakersOpen: number; }; /** * Get detailed performance metrics for a specific server */ getServerPerformanceMetrics(serverKey: string): ServerMetrics | null; /** * Get performance history for a specific server */ getServerPerformanceHistory(serverKey: string): ServerPerformanceHistory | null; /** * Get servers ranked by performance */ getRankedServersByPerformance(): Array<{ serverId: string; metrics: ServerMetrics; }>; /** * Get only healthy servers based on performance criteria */ getHealthyServersByPerformance(minScore?: number): Array<{ serverId: string; metrics: ServerMetrics; }>; /** * Shutdown the connection pool */ shutdown(): Promise<void>; } /** * Create ElectrumX connection pool with servers from configuration */ declare function createElectrumXPool(network: Network, customServers?: ElectrumXServer[], options?: Partial<ConnectionPoolOptions>): ElectrumXConnectionPool; /** * ElectrumX Fee Estimator * Advanced fee estimation with caching, validation, and fallback mechanisms */ interface FeeEstimate { priority: 'economy' | 'low' | 'medium' | 'high' | 'urgent'; confirmationTarget: number; feeRate: number; estimatedTime: string; confidence: 'low' | 'medium' | 'high'; source: 'electrumx' | 'fallback' | 'cached'; timestamp: number; } interface FeeEstimationOptions { includeFallback: boolean; cacheTimeout: number; validationThreshold: number; minFeeRate: number; maxConfirmationTarget: number; } /** * Advanced fee estimation with multiple strategies and validation */ declare class ElectrumXFeeEstimator { private cache; readonly provider: ElectrumXProvider | ElectrumXConnectionPool; private options; constructor(provider: ElectrumXProvider | ElectrumXConnectionPool, options?: Partial<FeeEstimationOptions>); /** * Get comprehensive fee estimates for all priority levels */ getAllFeeEstimates(): Promise<FeeEstimate[]>; /** * Get fee estimate for specific priority */ getFeeEstimate(priority: FeeEstimate['priority'], confirmationTarget?: number, estimatedTime?: string): Promise<FeeEstimate>; /** * Get optimal fee for transaction size */ getOptimalFee(transactionSizeBytes: number, priority?: FeeEstimate['priority']): Promise<{ totalFee: number; feeRate: number; estimate: FeeEstimate; }>; /** * Get fee estimates from multiple confirmation targets */ getFeeRangeEstimate(minTarget?: number, maxTarget?: number): Promise<{ estimates: Array<{ target: number; feeRate: number; estimatedTime: string; }>; recommended: FeeEstimate; }>; /** * Validate fee rate and apply corrections */ private validateAndProcessFeeRate; /** * Apply priority-based fee rate adjustments */ private applyPriorityAdjustment; /** * Calculate confidence level based on fee rate and target */ private calculateConfidence; /** * Get fallback estimate when ElectrumX is unavailable */ private getFallbackEstimate; /** * Map priority to provider priority format */ private mapPriorityToProviderPriority; /** * Get default confirmation target for priority */ private getDefaultTarget; /** * Get default fee rate for priority (fallback) */ private getDefaultFeeRate; /** * Convert confirmation target to priority */ private targetToPriority; /** * Get estimated confirmation time for target */ private getEstimatedTime; /** * Generate range of confirmation targets */ private generateTargetRange; /** * Check if cached estimate is still valid */ private isCacheValid; /** * Clear expired cache entries */ private cleanupCache; /** * Get cache statistics */ getCacheStats(): { size: number; hitRate: number; entries: Array<{ key: string; age: number; priority: string; feeRate: number; }>; }; /** * Clear all cached estimates */ clearCache(): void; /** * Update estimation options */ updateOptions(newOptions: Partial<FeeEstimationOptions>): void; /** * Export current fee estimates */ exportFeeEstimates(): Promise<{ timestamp: number; estimates: FeeEstimate[]; metadata: { provider: string; cacheSize: number; options: FeeEstimationOptions; }; }>; /** * Shutdown fee estimator */ shutdown(): void; } /** * Create ElectrumX fee estimator with default configuration */ declare function createElectrumXFeeEstimator(provider: ElectrumXProvider | ElectrumXConnectionPool, options?: Partial<FeeEstimationOptions>): ElectrumXFeeEstimator; /** * Create conservative fee estimator (longer cache, higher minimums) */ declare function createConservativeFeeEstimator(provider: ElectrumXProvider | ElectrumXConnectionPool): ElectrumXFeeEstimator; /** * Create aggressive fee estimator (shorter cache, lower minimums) */ declare function createAggressiveFeeEstimator(provider: ElectrumXProvider | ElectrumXConnectionPool): ElectrumXFeeEstimator; export { BaseProvider as B, type ConnectionPoolOptions as C, type ElectrumXConfig as E, type FeeEstimate as F, type ElectrumXServer as a, ElectrumXProvider as b, ElectrumXConnectionPool as c, createElectrumXProvider as d, createMultiEndpointProvider as e, createLocalDevelopmentProvider as f, createPublicProvider as g, createProviderFromEnvironment as h, createElectrumXPool as i, type FeeEstimationOptions as j, ElectrumXFeeEstimator as k, createElectrumXFeeEstimator as l, createConservativeFeeEstimator as m, createAggressiveFeeEstimator as n };