tstdio.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
tstdio.py (8385B)
---
1 from decimal import Decimal
2 import getpass
3 import datetime
4 import logging
5
6 from electrum import util
7 from electrum import WalletStorage, Wallet
8 from electrum.wallet_db import WalletDB
9 from electrum.util import format_satoshis
10 from electrum.bitcoin import is_address, COIN
11 from electrum.transaction import PartialTxOutput
12 from electrum.network import TxBroadcastError, BestEffortRequestFailed
13 from electrum.logging import console_stderr_handler
14
15 _ = lambda x:x # i18n
16
17 # minimal fdisk like gui for console usage
18 # written by rofl0r, with some bits stolen from the text gui (ncurses)
19
20
21 class ElectrumGui:
22
23 def __init__(self, config, daemon, plugins):
24 self.config = config
25 self.network = daemon.network
26 storage = WalletStorage(config.get_wallet_path())
27 if not storage.file_exists:
28 print("Wallet not found. try 'electrum create'")
29 exit()
30 if storage.is_encrypted():
31 password = getpass.getpass('Password:', stream=None)
32 storage.decrypt(password)
33
34 db = WalletDB(storage.read(), manual_upgrades=False)
35
36 self.done = 0
37 self.last_balance = ""
38
39 console_stderr_handler.setLevel(logging.CRITICAL)
40
41 self.str_recipient = ""
42 self.str_description = ""
43 self.str_amount = ""
44 self.str_fee = ""
45
46 self.wallet = Wallet(db, storage, config=config)
47 self.wallet.start_network(self.network)
48 self.contacts = self.wallet.contacts
49
50 util.register_callback(self.on_network, ['wallet_updated', 'network_updated', 'banner'])
51 self.commands = [_("[h] - displays this help text"), \
52 _("[i] - display transaction history"), \
53 _("[o] - enter payment order"), \
54 _("[p] - print stored payment order"), \
55 _("[s] - send stored payment order"), \
56 _("[r] - show own receipt addresses"), \
57 _("[c] - display contacts"), \
58 _("[b] - print server banner"), \
59 _("[q] - quit") ]
60 self.num_commands = len(self.commands)
61
62 def on_network(self, event, *args):
63 if event in ['wallet_updated', 'network_updated']:
64 self.updated()
65 elif event == 'banner':
66 self.print_banner()
67
68 def main_command(self):
69 self.print_balance()
70 c = input("enter command: ")
71 if c == "h" : self.print_commands()
72 elif c == "i" : self.print_history()
73 elif c == "o" : self.enter_order()
74 elif c == "p" : self.print_order()
75 elif c == "s" : self.send_order()
76 elif c == "r" : self.print_addresses()
77 elif c == "c" : self.print_contacts()
78 elif c == "b" : self.print_banner()
79 elif c == "n" : self.network_dialog()
80 elif c == "e" : self.settings_dialog()
81 elif c == "q" : self.done = 1
82 else: self.print_commands()
83
84 def updated(self):
85 s = self.get_balance()
86 if s != self.last_balance:
87 print(s)
88 self.last_balance = s
89 return True
90
91 def print_commands(self):
92 self.print_list(self.commands, "Available commands")
93
94 def print_history(self):
95 width = [20, 40, 14, 14]
96 delta = (80 - sum(width) - 4)/3
97 format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%" \
98 + "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
99 messages = []
100
101 for hist_item in reversed(self.wallet.get_history()):
102 if hist_item.tx_mined_status.conf:
103 timestamp = hist_item.tx_mined_status.timestamp
104 try:
105 time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
106 except Exception:
107 time_str = "unknown"
108 else:
109 time_str = 'unconfirmed'
110
111 label = self.wallet.get_label_for_txid(hist_item.txid)
112 messages.append(format_str % (time_str, label, format_satoshis(delta, whitespaces=True),
113 format_satoshis(hist_item.balance, whitespaces=True)))
114
115 self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))
116
117
118 def print_balance(self):
119 print(self.get_balance())
120
121 def get_balance(self):
122 if self.wallet.network.is_connected():
123 if not self.wallet.up_to_date:
124 msg = _( "Synchronizing..." )
125 else:
126 c, u, x = self.wallet.get_balance()
127 msg = _("Balance")+": %f "%(Decimal(c) / COIN)
128 if u:
129 msg += " [%f unconfirmed]"%(Decimal(u) / COIN)
130 if x:
131 msg += " [%f unmatured]"%(Decimal(x) / COIN)
132 else:
133 msg = _( "Not connected" )
134
135 return(msg)
136
137
138 def print_contacts(self):
139 messages = map(lambda x: "%20s %45s "%(x[0], x[1][1]), self.contacts.items())
140 self.print_list(messages, "%19s %25s "%("Key", "Value"))
141
142 def print_addresses(self):
143 messages = map(lambda addr: "%30s %30s "%(addr, self.wallet.get_label(addr)), self.wallet.get_addresses())
144 self.print_list(messages, "%19s %25s "%("Address", "Label"))
145
146 def print_order(self):
147 print("send order to " + self.str_recipient + ", amount: " + self.str_amount \
148 + "\nfee: " + self.str_fee + ", desc: " + self.str_description)
149
150 def enter_order(self):
151 self.str_recipient = input("Pay to: ")
152 self.str_description = input("Description : ")
153 self.str_amount = input("Amount: ")
154 self.str_fee = input("Fee: ")
155
156 def send_order(self):
157 self.do_send()
158
159 def print_banner(self):
160 for i, x in enumerate( self.wallet.network.banner.split('\n') ):
161 print( x )
162
163 def print_list(self, lst, firstline):
164 lst = list(lst)
165 self.maxpos = len(lst)
166 if not self.maxpos: return
167 print(firstline)
168 for i in range(self.maxpos):
169 msg = lst[i] if i < len(lst) else ""
170 print(msg)
171
172
173 def main(self):
174 while self.done == 0: self.main_command()
175
176 def do_send(self):
177 if not is_address(self.str_recipient):
178 print(_('Invalid Bitcoin address'))
179 return
180 try:
181 amount = int(Decimal(self.str_amount) * COIN)
182 except Exception:
183 print(_('Invalid Amount'))
184 return
185 try:
186 fee = int(Decimal(self.str_fee) * COIN)
187 except Exception:
188 print(_('Invalid Fee'))
189 return
190
191 if self.wallet.has_password():
192 password = self.password_dialog()
193 if not password:
194 return
195 else:
196 password = None
197
198 c = ""
199 while c != "y":
200 c = input("ok to send (y/n)?")
201 if c == "n": return
202
203 try:
204 tx = self.wallet.mktx(outputs=[PartialTxOutput.from_address_and_value(self.str_recipient, amount)],
205 password=password,
206 fee=fee)
207 except Exception as e:
208 print(repr(e))
209 return
210
211 if self.str_description:
212 self.wallet.set_label(tx.txid(), self.str_description)
213
214 print(_("Please wait..."))
215 try:
216 self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
217 except TxBroadcastError as e:
218 msg = e.get_message_for_gui()
219 print(msg)
220 except BestEffortRequestFailed as e:
221 msg = repr(e)
222 print(msg)
223 else:
224 print(_('Payment sent.'))
225 #self.do_clear()
226 #self.update_contacts_tab()
227
228 def network_dialog(self):
229 print("use 'electrum setconfig server/proxy' to change your network settings")
230 return True
231
232
233 def settings_dialog(self):
234 print("use 'electrum setconfig' to change your settings")
235 return True
236
237 def password_dialog(self):
238 return getpass.getpass()
239
240
241 # XXX unused
242
243 def run_receive_tab(self, c):
244 #if c == 10:
245 # out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
246 return
247
248 def run_contacts_tab(self, c):
249 pass