#!/usr/bin/env python3 """ Bitcoin Dust Economic Analysis Tool Calculates minimum spendable amounts and dust thresholds across fee environments """ import json import math from typing import Dict, List, Optional, Any from dataclasses import dataclass from datetime import datetime @dataclass class TxOutput: """Transaction output configuration""" value: int # satoshis script_type: str # 'legacy', 'segwit', 'taproot' @dataclass class FeeEnvironment: """Fee rate environment""" sat_per_vbyte: float description: str class DustAnalyzer: """Bitcoin dust economic impossibility calculator""" # Transaction size constants (in vbytes) SIZES = { 'legacy': { 'input': 148, # P2PKH input 'output': 34, # P2PKH output 'base': 10, # Transaction overhead }, 'segwit': { 'input': 68, # P2WPKH input (witness discount applied) 'output': 31, # P2WPKH output 'base': 11, # SegWit transaction overhead }, 'taproot': { 'input': 64, # P2TR input 'output': 43, # P2TR output 'base': 11, # Taproot transaction overhead } } # Dust thresholds (in satoshis) DUST_THRESHOLDS = { 'legacy': 546, 'segwit': 294, 'taproot': 330 } def __init__(self): self.fee_environments = [ FeeEnvironment(1.0, "Low fee (1 sat/vbyte)"), FeeEnvironment(5.0, "Normal fee (5 sat/vbyte)"), FeeEnvironment(10.0, "High fee (10 sat/vbyte)"), FeeEnvironment(25.0, "Very high fee (25 sat/vbyte)"), FeeEnvironment(50.0, "Extreme fee (50 sat/vbyte)"), ] def calculate_tx_size(self, inputs: int, outputs: int, script_type: str) -> int: """Calculate transaction size in vbytes""" sizes = self.SIZES[script_type] return sizes['base'] + (inputs * sizes['input']) + (outputs * sizes['output']) def calculate_fee(self, inputs: int, outputs: int, script_type: str, fee_rate: float) -> int: """Calculate transaction fee in satoshis""" tx_size = self.calculate_tx_size(inputs, outputs, script_type) return math.ceil(tx_size * fee_rate) def calculate_minimum_spendable(self, utxo_value: int, script_type: str, fee_rate: float, target_outputs: int = 1) -> Dict[str, Any]: """Calculate if UTXO is economically spendable""" # Fee to spend this UTXO fee = self.calculate_fee(1, target_outputs, script_type, fee_rate) # Minimum value needed to be spendable min_spendable = fee + (target_outputs * self.DUST_THRESHOLDS[script_type]) # Economic analysis is_spendable = utxo_value >= min_spendable is_dust = utxo_value < self.DUST_THRESHOLDS[script_type] # Waste ratio (fee as percentage of UTXO value) waste_ratio = (fee / utxo_value * 100) if utxo_value > 0 else 100 return { 'utxo_value': utxo_value, 'script_type': script_type, 'fee_rate': fee_rate, 'fee_to_spend': fee, 'min_spendable': min_spendable, 'is_spendable': is_spendable, 'is_dust': is_dust, 'waste_ratio': waste_ratio, 'economic_efficiency': 'efficient' if waste_ratio < 10 else 'inefficient' } def generate_dust_analysis(self) -> Dict[str, Any]: """Generate comprehensive dust analysis across fee environments""" analysis = { 'timestamp': datetime.now().isoformat(), 'fee_environments': [], 'dust_thresholds': self.DUST_THRESHOLDS, 'economic_impossibility': {} } for env in self.fee_environments: env_data = { 'fee_rate': env.sat_per_vbyte, 'description': env.description, 'script_types': {} } for script_type in ['legacy', 'segwit', 'taproot']: # Calculate minimum spendable for different UTXO values test_values = [100, 500, 1000, 5000, 10000, 50000] script_data = { 'dust_threshold': self.DUST_THRESHOLDS[script_type], 'min_spendable_1out': self.calculate_fee(1, 1, script_type, env.sat_per_vbyte) + self.DUST_THRESHOLDS[script_type], 'min_spendable_2out': self.calculate_fee(1, 2, script_type, env.sat_per_vbyte) + (2 * self.DUST_THRESHOLDS[script_type]), 'test_cases': [] } for value in test_values: result = self.calculate_minimum_spendable(value, script_type, env.sat_per_vbyte) script_data['test_cases'].append(result) env_data['script_types'][script_type] = script_data analysis['fee_environments'].append(env_data) # Calculate economic impossibility points for script_type in ['legacy', 'segwit', 'taproot']: analysis['economic_impossibility'][script_type] = {} for env in self.fee_environments: # Point where spending costs more than the value fee = self.calculate_fee(1, 1, script_type, env.sat_per_vbyte) impossibility_point = fee + self.DUST_THRESHOLDS[script_type] analysis['economic_impossibility'][script_type][env.sat_per_vbyte] = { 'impossibility_point': impossibility_point, 'fee_component': fee, 'dust_component': self.DUST_THRESHOLDS[script_type] } return analysis def calculate_consolidation_economics(self, utxo_values: List[int], script_type: str, fee_rate: float) -> Dict[str, Any]: """Analyze economics of UTXO consolidation""" num_inputs = len(utxo_values) total_value = sum(utxo_values) # Cost to consolidate all inputs into 1 output consolidation_fee = self.calculate_fee(num_inputs, 1, script_type, fee_rate) net_result = total_value - consolidation_fee # Cost to spend each individually (for comparison) individual_fees = sum( self.calculate_fee(1, 1, script_type, fee_rate) for _ in utxo_values ) # Economic benefit fee_savings = individual_fees - consolidation_fee savings_percentage = (fee_savings / individual_fees * 100) if individual_fees > 0 else 0 return { 'num_inputs': num_inputs, 'total_value': total_value, 'script_type': script_type, 'fee_rate': fee_rate, 'consolidation_fee': consolidation_fee, 'net_result': net_result, 'individual_spending_cost': individual_fees, 'fee_savings': fee_savings, 'savings_percentage': savings_percentage, 'is_economical': fee_savings > 0, 'break_even_inputs': math.ceil(consolidation_fee / self.calculate_fee(1, 1, script_type, fee_rate)) } def main(): """Run dust analysis and generate results""" analyzer = DustAnalyzer() # Generate comprehensive analysis analysis = analyzer.generate_dust_analysis() # Test consolidation economics consolidation_test = analyzer.calculate_consolidation_economics( [1000, 1500, 2000, 2500, 3000], 'segwit', 5.0 ) results = { 'dust_analysis': analysis, 'consolidation_example': consolidation_test } # Save results with open('dust_analysis_results.json', 'w') as f: json.dump(results, f, indent=2) print("✅ Dust analysis complete") print(f"📊 Generated analysis for {len(analysis['fee_environments'])} fee environments") print(f"💰 Consolidation savings: {consolidation_test['savings_percentage']:.1f}%") return results if __name__ == "__main__": main()