#!/usr/bin/env python3 #this script will help to fix tx_fees wallet bug #also added an uninstall button to remove any bal data from wallet #still very work in progress. # #have to be executed from electrum source code directory in example /home/user/projects/electrum/ # import sys import os import json from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QWidget, QFileDialog, QGroupBox, QTextEdit) from PyQt6.QtCore import Qt from electrum.storage import WalletStorage from electrum.util import MyEncoder default_fees = 100 class WalletUtilityGUI(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('BAL Wallet Utility') self.setFixedSize(500, 400) # Central widget central_widget = QWidget() self.setCentralWidget(central_widget) # Main layout layout = QVBoxLayout(central_widget) # Wallet input group wallet_group = QGroupBox("Wallet Settings") wallet_layout = QVBoxLayout(wallet_group) # Wallet path wallet_path_layout = QHBoxLayout() wallet_path_layout.addWidget(QLabel("Wallet Path:")) self.wallet_path_edit = QLineEdit() self.wallet_path_edit.setPlaceholderText("Select wallet path...") wallet_path_layout.addWidget(self.wallet_path_edit) self.browse_btn = QPushButton("Browse...") self.browse_btn.clicked.connect(self.browse_wallet) wallet_path_layout.addWidget(self.browse_btn) wallet_layout.addLayout(wallet_path_layout) # Password password_layout = QHBoxLayout() password_layout.addWidget(QLabel("Password:")) self.password_edit = QLineEdit() self.password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.password_edit.setPlaceholderText("Enter password (if encrypted)") password_layout.addWidget(self.password_edit) wallet_layout.addLayout(password_layout) layout.addWidget(wallet_group) # Output area output_group = QGroupBox("Output") output_layout = QVBoxLayout(output_group) self.output_text = QTextEdit() self.output_text.setReadOnly(True) output_layout.addWidget(self.output_text) layout.addWidget(output_group) # Action buttons buttons_layout = QHBoxLayout() self.fix_btn = QPushButton("Fix") self.fix_btn.clicked.connect(self.fix_wallet) self.fix_btn.setEnabled(False) buttons_layout.addWidget(self.fix_btn) self.uninstall_btn = QPushButton("Uninstall") self.uninstall_btn.clicked.connect(self.uninstall_wallet) self.uninstall_btn.setEnabled(False) buttons_layout.addWidget(self.uninstall_btn) layout.addLayout(buttons_layout) # Connections to enable buttons when path is entered self.wallet_path_edit.textChanged.connect(self.check_inputs) def browse_wallet(self): file_path, _ = QFileDialog.getOpenFileName( self, "Select Wallet", "", "Electrum Wallet (*.dat)" ) if file_path: self.wallet_path_edit.setText(file_path) def check_inputs(self): wallet_path = self.wallet_path_edit.text().strip() has_path = bool(wallet_path) and os.path.exists(wallet_path) self.fix_btn.setEnabled(has_path) self.uninstall_btn.setEnabled(has_path) def log_message(self, message): self.output_text.append(message) def fix_will_settings_tx_fees(self, json_wallet): tx_fees = json_wallet.get('will_settings',{}).get('tx_fees',False) if tx_fees: json_wallet['will_settings']['baltx_fees'] = json_wallet.get('will_settings',{}).get('tx_fees', default_fees) del json_wallet['will_settings']['tx_fees'] return True return False def uninstall_bal(self, json_wallet): if 'will_settings' in json_wallet: del json_wallet['will_settings'] if 'will' in json_wallet: del json_wallet['will'] if 'heirs' in json_wallet: del json_wallet['heirs'] return True def save_wallet(self, json_wallet, storage): try: human_readable = not storage.is_encrypted() storage.write(json.dumps( json_wallet, indent=4 if human_readable else None, sort_keys=bool(human_readable), cls=MyEncoder, )) return True except Exception as e: self.log_message(f"Save error: {str(e)}") return False def fix_wallet(self): self.process_wallet('fix') def uninstall_wallet(self): self.log_message("WARNING: This will remove all BAL settings. This operation cannot be undone.") self.process_wallet('uninstall') def process_wallet(self, command): wallet_path = self.wallet_path_edit.text().strip() password = self.password_edit.text() if not wallet_path: self.log_message("ERROR: Please enter wallet path") return if not os.path.exists(wallet_path): self.log_message("ERROR: Wallet not found") return try: self.log_message(f"Processing wallet: {wallet_path}") storage = WalletStorage(wallet_path) # Decrypt if necessary if storage.is_encrypted(): if not password: self.log_message("ERROR: Wallet is encrypted, please enter password") return try: storage.decrypt(password) self.log_message("Wallet decrypted successfully") except Exception as e: self.log_message(f"ERROR: Wrong password: {str(e)}") return # Read wallet data = storage.read() json_wallet = json.loads(data) have_to_save = False message = "" if command == 'fix': have_to_save = self.fix_will_settings_tx_fees(json_wallet) message = "Fix applied successfully" if have_to_save else "No fix needed" elif command == 'uninstall': have_to_save = self.uninstall_bal(json_wallet) message = "BAL uninstalled successfully" if have_to_save else "No BAL settings found to uninstall" if have_to_save: if self.save_wallet(json_wallet, storage): self.log_message(f"SUCCESS: {message}") else: self.log_message("ERROR: Failed to save wallet") else: self.log_message(f"INFO: {message}") except Exception as e: error_msg = f"ERROR: Processing failed: {str(e)}" self.log_message(error_msg) def main(): app = QApplication(sys.argv) # Check if dependencies are available try: from electrum.storage import WalletStorage from electrum.util import MyEncoder except ImportError as e: print(f"ERROR: Cannot import Electrum dependencies: {str(e)}") return 1 window = WalletUtilityGUI() window.show() return app.exec() if __name__ == '__main__': sys.exit(main())