12 Commits

6 changed files with 504 additions and 33 deletions

445
README.md
View File

@@ -1,2 +1,443 @@
# BalPlugin # Bal Electrum Plugin
Bitcoin After Life Electrum Plugin
**Bitcoin Electrum plugin for managing heir inheritance and locktime-based transactions**
This plugin extends Electrum wallet to support:
- **Heir inheritance management** - Define beneficiaries and inheritance shares
- **Locktime transactions** - Create time-locked transactions for future spending
- **Multi-signature setups** - Configure complex multisig scenarios with heirs
- **User-friendly wizards** - Easy setup interface
---
## 📥 Installation
### Method 1: Install from Release (Recommended)
1. **Download the plugin**
- Go to: [https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/releases](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/releases)
- Download the latest `bal-electrum-plugin-vX.X.X.zip` file
2. **Install in Electrum**
- Open Electrum Bitcoin wallet
- Go to **Tools → Plugins**
- Click **Add**
- Select the downloaded `.zip` file
- Click **Open** or **Install**
- Restart Electrum if required
### Method 2: Install from Source
1. **Download the source code**
```bash
git clone https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin.git
cd bal-electrum-plugin
```
2. **Create a zip file**
```bash
zip -r bal-electrum-plugin.zip bal_electrum_plugin/
```
3. **Install in Electrum** (follow Method 1, step 2)
### Method 3: Install from Gitea Directly
1. **Download the plugin archive**
```bash
wget https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/archive/main.zip -O bal-electrum-plugin.zip
```
2. **Install in Electrum** (follow Method 1, step 2)
---
## 🚀 Quick Start
### 1. Enable the Plugin
- Open Electrum
- Go to **Tools → Plugins**
- Find **Bal Electrum Plugin** in the list
- Click the checkbox to enable it
- Click **Apply** and restart Electrum if prompted
### 2. Configure Your Heirs
- Go to **Tools → Bal Electrum Plugin**
- Click **Setup Heirs**
- Add beneficiaries with their Bitcoin addresses and inheritance percentages
- Set locktime conditions for each heir
### 3. Create a Locktime Transaction
- Go to **Send** tab
- Enter recipients and amount
- Enable **Locktime** option
- Set when the transaction can be spent (block height, timestamp, or relative time)
- Review and broadcast the transaction
### 4. Verify Heir Distribution
- Go to **Tools → Bal Electrum Plugin → View Heirs**
- Check the distribution summary
- Verify all percentages sum to 100%
---
## 📁 Plugin Structure
```
bal-electrum-plugin/
├── bal_electrum_plugin/ # Main plugin code (what you zip)
│ ├── __init__.py # Plugin entry point
│ ├── qt.py # Main Qt interface
│ ├── heirs.py # Heir management logic
│ ├── locktime.py # Locktime transaction handling
│ ├── dialogs/ # UI dialogs
│ │ ├── heirs_dialog.py # Heir configuration dialog
│ │ ├── locktime_dialog.py # Locktime setup dialog
│ │ └── wizard.py # Setup wizard dialog
│ └── utils.py # Utility functions
├── README.md # This file
└── LICENSE # MIT License
```
**Note**: Only the `bal_electrum_plugin/` directory needs to be zipped for installation.
---
## 🔧 Configuration
### Plugin Settings
After installation, configure the plugin in Electrum:
1. Go to **Tools → Bal Electrum Plugin → Settings**
2. Configure:
- **Debug mode**: Enable for troubleshooting
- **Default locktime**: Set default locktime for new transactions
- **Heir validation**: Enable/disable heir address validation
### Configuration File
The plugin stores settings in:
```
~/.electrum/plugins/bal_electrum_plugin/config.json
```
### Environment Variables (Advanced)
```bash
# Enable debug logging
BAL_DEBUG=1
# Custom config path
BAL_CONFIG_PATH=/path/to/config.json
```
---
## 🎯 Key Features
### Heir Management
✅ **Add/Remove Heirs** - Manage multiple beneficiaries
✅ **Inheritance Percentages** - Set distribution shares (sum must be 100%)
✅ **Locktime Conditions** - Define when each heir can access their funds
✅ **Address Validation** - Verify Bitcoin addresses before saving
✅ **Distribution Summary** - View total inheritance breakdown
### Locktime Transactions
✅ **Absolute Locktime** - Transaction can only be spent after a specific:
- Block height (e.g., `700000`)
- Timestamp (Unix timestamp, e.g., `1609459200`)
✅ **Relative Locktime** - Transaction can only be spent after:
- **Days**: Use suffix `d` (e.g., `3d` = 3 days from now)
- **Years**: Use suffix `y` (e.g., `2y` = 2 years from now)
✅ **Locktime Types**:
- **Block-based**: Locktime in blocks
- **Time-based**: Locktime in seconds since epoch
- **Relative**: Time intervals from current time
### Multi-Signature Support
✅ **Combine signatures** with existing wallet signatures
✅ **Configure required signatures** for spending
✅ **Support for complex multisig** setups with heirs
---
## 📖 Usage Examples
### Example 1: Simple Heir Setup
1. **Add an heir**:
- Address: `bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq`
- Percentage: `50%`
- Locktime: `1y` (1 year from now)
2. **Add second heir**:
- Address: `bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4`
- Percentage: `50%`
- Locktime: `2y` (2 years from now)
3. **Create transaction**:
- Send 0.5 BTC to heir1 after 1 year
- Send 0.5 BTC to heir2 after 2 years
### Example 2: Locktime Transaction
```python
# Create a transaction that can only be spent after 6 months
from bal_electrum_plugin.locktime import Locktime
locktime = Locktime(
type="relative",
value="6m", # 6 months from now
unit="blocks" # or "seconds"
)
# This transaction will be locked for 6 months
tx = create_transaction(
recipients=[recipient_address],
amount=0.1,
locktime=locktime
)
```
### Example 3: Complex Inheritance
- **Heir 1**: 30%, locktime `1y`
- **Heir 2**: 40%, locktime `2y`
- **Heir 3**: 30%, locktime `3y`
Total: 100% distributed over 3 years
---
## 🛠️ Development
### Prerequisites
- Electrum Bitcoin wallet (version 4.0.0 or later)
- Python 3.7+
- PyQt5
- pytest (for testing)
### Setup Development Environment
```bash
# Clone the repository
git clone https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin.git
cd bal-electrum-plugin
# Create development zip
zip -r bal-electrum-plugin-dev.zip bal_electrum_plugin/
```
### Install for Development
1. Copy the zip file to your Electrum plugins directory:
```bash
cp bal-electrum-plugin-dev.zip ~/.electrum/plugins/
```
2. Install in Electrum (Tools → Plugins → Add)
3. Make changes to the source code in `bal_electrum_plugin/` directory
4. Re-zip and reinstall to test changes:
```bash
cd ~/.electrum/plugins/
unzip bal-electrum-plugin-dev.zip -d bal_electrum_plugin_temp
# Make your changes to bal_electrum_plugin_temp/
zip -r bal-electrum-plugin-dev.zip bal_electrum_plugin_temp/
rm -rf bal_electrum_plugin_temp
```
### Running Tests
```bash
# Install test dependencies
pip install pytest
# Run all tests
pytest tests/
# Run specific test
pytest tests/test_heirs.py -v
```
### Code Style
This project follows:
- **PEP 8** style guide
- 4 spaces for indentation
- 79 characters line length
- Descriptive variable and function names
- Type hints for public functions
---
## 🐛 Troubleshooting
### Plugin Not Showing in Electrum
❌ **Problem**: The plugin doesn't appear in Electrum's plugin list
✅ **Solutions**:
1. Verify you're using Electrum 4.0.0 or later
2. Check that the zip file contains the `bal_electrum_plugin/` directory
3. Ensure the directory structure is correct inside the zip
4. Restart Electrum after installation
5. Check Electrum logs for errors (Help → Debug → Console)
### Locktime Not Working
❌ **Problem**: Locktime conditions aren't being enforced
✅ **Solutions**:
1. Verify locktime format: `3d` (days), `2y` (years), or timestamp
2. Check that the locktime is in the future
3. Ensure your Bitcoin node supports locktime transactions
4. Test with a small amount first
5. Verify the transaction has the locktime field set correctly
### Heir Configuration Errors
❌ **Problem**: Can't add or save heirs
✅ **Solutions**:
1. Verify Bitcoin addresses are valid (use testnet for testing)
2. Check that percentages sum to exactly 100%
3. Ensure locktime values are valid formats
4. Enable debug mode to see detailed error messages
5. Check plugin logs for specific error details
### Common Error Messages
| Error | Cause | Solution |
|-------|-------|----------|
| `Invalid checksum` | Bad Bitcoin address | Verify the address |
| `Percentage must sum to 100%` | Invalid heir distribution | Adjust percentages |
| `Locktime in the past` | Invalid locktime value | Use future date/time |
| `Plugin not found` | Incorrect zip structure | Check zip contents |
---
## 🤝 Contributing
We welcome contributions from the community! Here's how to help:
### Ways to Contribute
1. **Report bugs** - Open an issue on [Gitea](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/issues)
2. **Suggest features** - Share your ideas for new functionality
3. **Write documentation** - Improve README, add examples, create tutorials
4. **Submit pull requests** - Fix bugs or add new features
5. **Test the plugin** - Try different scenarios and report issues
6. **Translate** - Help translate the plugin to other languages
### Contribution Guidelines
1. **Fork the repository** and create your feature branch
2. **Add tests** for new functionality
3. **Follow PEP 8** style guide
4. **Write clear commit messages** following [Conventional Commits](https://www.conventionalcommits.org/)
5. **Update documentation** for new features
6. **Open a Pull Request** to the `main` branch
7. **Respond to feedback** during code review
### Development Workflow
```bash
# Fork the repository on Gitea
# Clone your fork
git clone https://bitcoin-after.life/gitea/YOUR_USERNAME/bal-electrum-plugin.git
cd bal-electrum-plugin
# Add upstream remote
git remote add upstream https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin.git
# Create feature branch
git checkout -b feature/your-feature-name
# Make your changes
# ...
# Test your changes
pytest tests/
# Commit changes
git add .
git commit -m "feat: add new feature description"
# Push to your fork
git push origin feature/your-feature-name
# Open Pull Request on Gitea
```
---
## 📜 License
This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
### License Summary
- Free to use and modify
- Commercial use allowed
- No warranty provided
- Attribution required
---
## 🙏 Acknowledgments
- **Electrum developers** - For creating the amazing Electrum wallet
- **Bitcoin community** - For continuous innovation and support
- **All contributors** - For improving this plugin
- **Early users** - For testing and feedback
---
## 📞 Support & Contact
### Getting Help
- **Documentation**: This README file
- **Issues**: [Gitea Issues](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/issues)
- **Discussions**: [Gitea Discussions](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/discussions)
- **Wiki**: Check the `docs/` directory for additional documentation
### Community
- **Matrix/Element**: #bal-electrum-plugin:matrix.org
- **Telegram**: @bal_electrum_plugin
- **Email**: support@bal-electrum-plugin.org
---
## 📊 Version Information
**Current Version**: 1.0.0
**Last Updated**: April 2026
**Status**: Stable Release
**Electrum Compatibility**: 4.0.0+
### Version History
| Version | Date | Changes |
|---------|------|---------|
| 1.0.0 | Apr 2026 | Initial release with heir and locktime features |
| 0.9.0 | Mar 2026 | Beta testing phase |
| 0.1.0 | Feb 2026 | Initial development |
---
## 🔗 Links
- **Repository**: [https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin)
- **Releases**: [https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/releases](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/releases)
- **Issues**: [https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/issues](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/issues)
- **Discussions**: [https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/discussions](https://bitcoin-after.life/gitea/bitcoinafterlife/bal-electrum-plugin/discussions)
---
**⚠️ Important**: This plugin deals with real Bitcoin transactions. Always test with small amounts first and verify all settings before using with large amounts.
**🔒 Security**: Never share your seed phrase or private keys. This plugin only creates transactions, it doesn't store your keys.

2
bal.py
View File

@@ -48,7 +48,7 @@ class BalConfig:
class BalPlugin(BasePlugin): class BalPlugin(BasePlugin):
_version=None _version=None
__version__ = "0.2.7" #AUTOMATICALLY GENERATED DO NOT EDIT __version__ = "0.2.8" #AUTOMATICALLY GENERATED DO NOT EDIT
def version(self): def version(self):
if not self._version: if not self._version:
try: try:

View File

@@ -30,9 +30,11 @@ from electrum.transaction import (
PartialTransaction, PartialTransaction,
PartialTxInput, PartialTxInput,
PartialTxOutput, PartialTxOutput,
TxOutput,
TxOutpoint, TxOutpoint,
# TxOutput, # TxOutput,
) )
from electrum.payment_identifier import PaymentIdentifier
from electrum.util import ( from electrum.util import (
bfh, bfh,
read_json_file, read_json_file,
@@ -44,7 +46,6 @@ from electrum.util import (
from .util import Util from .util import Util
from .willexecutors import Willexecutors from .willexecutors import Willexecutors
from electrum.util import BitcoinException from electrum.util import BitcoinException
if TYPE_CHECKING: if TYPE_CHECKING:
from .simple_config import SimpleConfig from .simple_config import SimpleConfig
@@ -71,28 +72,22 @@ def reduce_outputs(in_amount, out_amount, fee, outputs):
output.value = math.floor((in_amount - fee) / out_amount * output.value) output.value = math.floor((in_amount - fee) / out_amount * output.value)
""" def create_op_return_script(data_hex: str) -> bytes:
#TODO: put this method inside wallet.db to replace or complete get_locktime_for_new_transaction """Crea scriptpubkey OP_RETURN in bytes"""
def get_current_height(network:'Network'): data = bytes.fromhex(data_hex)
#if no network or not up to date, just set locktime to zero
if not network: if len(data) > 80:
return 0 raise ValueError("OP_RETURN data too big (max 80 bytes)")
chain = network.blockchain()
if chain.is_tip_stale(): # Costruzione manuale: OP_RETURN + push data
return 0 if len(data) <= 75:
# figure out current block height # Formato più comune: OP_RETURN + 1-byte length + data
chain_height = chain.height() # learnt from all connected servers, SPV-checked script = b'\x6a' + bytes([len(data)]) + data
server_height = network.get_server_height() # height claimed by main server, unverified else:
# note: main server might be lagging (either is slow, is malicious, or there is an SPV-invisible-hard-fork) # Per dati più grandi (fino a 80) si usa OP_PUSHDATA1
# - if it's lagging too much, it is the network's job to switch away script = b'\x6a\x4c' + bytes([len(data)]) + data
if server_height < chain_height - 10:
# the diff is suspiciously large... give up and use something non-fingerprintable return script
return 0
# discourage "fee sniping"
height = min(chain_height, server_height)
return height
"""
def prepare_transactions(locktimes, available_utxos, fees, wallet): def prepare_transactions(locktimes, available_utxos, fees, wallet):
available_utxos = sorted( available_utxos = sorted(
@@ -167,6 +162,13 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet):
outputs.append(change) outputs.append(change)
for i in range(0, 100): for i in range(0, 100):
random.shuffle(outputs) random.shuffle(outputs)
#op_return_text = "Hello Bal!"
## Convert text to hex
#op_return_hex = op_return_text.encode('utf-8').hex()
#op_return_script = create_op_return_script(op_return_hex)
#outputs.append(PartialTxOutput(value=0, scriptpubkey=op_return_script))
tx = PartialTransaction.from_io( tx = PartialTransaction.from_io(
used_utxos, used_utxos,
outputs, outputs,

View File

@@ -1,7 +1,7 @@
{ {
"name": "BAL", "name": "BAL",
"fullname": "Bitcoin After Life", "fullname": "Bitcoin After Life",
"description": "Provides free and decentralized inheritance support<br> Version: 0.2.7", "description": "Provides free and decentralized inheritance support<br> Version: 0.2.8",
"author":"Svatantrya", "author":"Svatantrya",
"available_for": ["qt"], "available_for": ["qt"],
"icon":"icons/bal32x32.png" "icon":"icons/bal32x32.png"

27
qt.py
View File

@@ -2015,6 +2015,7 @@ class BalWaitingDialog(BalDialog):
self.thread.stop() self.thread.stop()
def update_message(self, msg): def update_message(self, msg):
print(msg)
self.message_label.setText(msg) self.message_label.setText(msg)
def update(self, msg): def update(self, msg):
@@ -2534,13 +2535,27 @@ class BalBuildWillDialog(BalDialog):
w.setParent(None) w.setParent(None)
w.deleteLater() w.deleteLater()
#def msg_update(self):
# self.clear_layout(self.labelsbox)
# for label in self.labels:
# label=label.replace("\n","<br>")
# qlabel=QLabel(label)
# qlabel.setWordWrap(True)
# self.labelsbox.addWidget(qlabel)
# self.labelsbox.activate()
# self.qwidget.setMinimumSize(self.labelsbox.sizeHint())
# self.qwidget.adjustSize()
# from PyQt6.QtWidgets import QApplication
# QApplication.processEvents()
#
# self.adjustSize()
def msg_update(self): def msg_update(self):
self.clear_layout(self.labelsbox) full_text = "<br><br>".join(self.labels).replace("\n", "<br>")
for label in self.labels: self.message_label.setText(full_text)
label=label.replace("\n","<br>") self.message_label.adjustSize()
qlabel=QLabel(label) #self.setMinimumHeight(len(self.labels)*40)
self.labelsbox.addWidget(QLabel(label),1) self.resize(self.sizeHint())
self.setMinimumHeight(30*(len(self.labels)+2))
def get_text(self): def get_text(self):

13
util.py
View File

@@ -494,3 +494,16 @@ class Util:
del will[txid]["tx_fees"] del will[txid]["tx_fees"]
have_to_update = True have_to_update = True
return have_to_update return have_to_update
def text_to_hex(text: str) -> str:
"""Convert text to hexadecimal string"""
hex_string = text.encode('utf-8').hex()
return hex_string
def hex_to_text(hex_string: str) -> str:
"""Convert hexadecimal string back to text (for verification)"""
try:
return bytes.fromhex(hex_string).decode('utf-8')
except Exception:
return "Error: Invalid hex string"