electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

stdio.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