-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstacks_address_dialog.py
More file actions
122 lines (95 loc) · 4.38 KB
/
stacks_address_dialog.py
File metadata and controls
122 lines (95 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""
Extended Address Dialog with STX Address and Balance
Shows STX address and balance information in Electrum's address details dialog.
"""
from typing import TYPE_CHECKING
import threading
import urllib.request
import json
import ssl
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QLabel, QLineEdit
from electrum.i18n import _
from electrum.gui.qt.address_dialog import AddressDialog
from electrum.gui.qt.util import ButtonsLineEdit
from .stacks_wire import bitcoin_address_to_stx_address, StacksNetwork
from .stacks_preferences import get_stacks_network, get_stacks_api_url
if TYPE_CHECKING:
from electrum.gui.qt.main_window import ElectrumWindow
class StacksAddressDialog(AddressDialog):
"""Extended AddressDialog that shows STX address and balance."""
def __init__(self, window: 'ElectrumWindow', address: str, *, parent=None):
super().__init__(window, address, parent=parent)
self._config = window.config
self.stacks_network = get_stacks_network(self._config)
# Find the layout and insert STX info after the address field
vbox = self.layout()
# Find position after address (index 2 = after "Address:" label and addr_e)
insert_pos = 2
# Try to convert to STX address
try:
self.stx_address = bitcoin_address_to_stx_address(address, self.stacks_network)
# Add STX Address field
vbox.insertWidget(insert_pos, QLabel(_("STX Address") + ":"))
insert_pos += 1
self.stx_addr_e = ButtonsLineEdit(self.stx_address)
self.stx_addr_e.addCopyButton()
self.stx_addr_e.setReadOnly(True)
vbox.insertWidget(insert_pos, self.stx_addr_e)
insert_pos += 1
# Add STX Balance field
vbox.insertWidget(insert_pos, QLabel(_("STX Balance") + ":"))
insert_pos += 1
self.stx_balance_e = QLineEdit()
self.stx_balance_e.setReadOnly(True)
self.stx_balance_e.setText(_("Fetching..."))
vbox.insertWidget(insert_pos, self.stx_balance_e)
# Fetch balance asynchronously
self._fetch_stx_balance()
except Exception:
# Address type not supported - show message
vbox.insertWidget(insert_pos, QLabel(_("STX Address") + ":"))
insert_pos += 1
unsupported_label = QLineEdit(_("(unsupported address type)"))
unsupported_label.setReadOnly(True)
unsupported_label.setStyleSheet("color: gray; font-style: italic;")
vbox.insertWidget(insert_pos, unsupported_label)
self.stx_address = None
def _fetch_stx_balance(self):
"""Fetch STX balance from Stacks API in a background thread."""
stx_address = self.stx_address
api_url = get_stacks_api_url(self._config, f"/v2/accounts/{stx_address}")
def fetch():
try:
req = urllib.request.Request(api_url, headers={'Accept': 'application/json'})
# Create SSL context
try:
import certifi
ssl_context = ssl.create_default_context(cafile=certifi.where())
except ImportError:
ssl_context = ssl.create_default_context()
with urllib.request.urlopen(req, timeout=10, context=ssl_context) as response:
data = json.loads(response.read().decode())
balance_hex = data.get('balance', '0')
if balance_hex.startswith('0x'):
balance_hex = balance_hex[2:]
balance_micro = int(balance_hex, 16)
balance_stx = balance_micro / 1_000_000
return f"{balance_stx:,.6f} STX"
except urllib.error.HTTPError as e:
if e.code == 404:
return "0.000000 STX (new address)"
return f"API error: {e.code}"
except Exception as e:
return f"Error: {str(e)[:30]}"
def run_fetch():
result = fetch()
# Schedule UI update on main thread
from PyQt6.QtCore import QMetaObject, Q_ARG
QMetaObject.invokeMethod(
self.stx_balance_e, "setText",
Qt.ConnectionType.QueuedConnection,
Q_ARG(str, result)
)
thread = threading.Thread(target=run_fetch, daemon=True)
thread.start()