2011-11-04 18:00:37 +01:00
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2011 thomasv@gitorious
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2012-02-01 20:27:03 +01:00
import re , sys , getpass
2011-11-06 11:13:58 +01:00
2011-11-14 20:35:54 +01:00
from optparse import OptionParser
2012-01-19 17:11:36 +01:00
from wallet import Wallet
from interface import Interface
2012-02-06 07:48:52 +01:00
from decimal import Decimal
2012-01-19 17:25:25 +01:00
# URL decode
_ud = re . compile ( ' % ([0-9a-hA-H] {2} ) ' , re . MULTILINE )
urldecode = lambda x : _ud . sub ( lambda m : chr ( int ( m . group ( 1 ) , 16 ) ) , x )
2012-02-06 07:48:52 +01:00
from wallet import format_satoshis
2012-02-03 08:02:12 +01:00
2011-11-04 18:00:37 +01:00
if __name__ == ' __main__ ' :
2012-02-11 13:14:12 +01:00
known_commands = [ ' help ' , ' validateaddress ' , ' balance ' , ' contacts ' , ' create ' , ' payto ' , ' sendtx ' , ' password ' , ' newaddress ' , ' addresses ' , ' history ' , ' label ' , ' mktx ' , ' seed ' , ' import ' , ' signmessage ' , ' verifymessage ' , ' eval ' , ' gtk ' , ' qt ' ]
2011-11-14 20:35:54 +01:00
usage = " usage: % prog [options] command args \n Commands: " + ( ' , ' . join ( known_commands ) )
parser = OptionParser ( usage = usage )
2011-11-29 11:23:49 +01:00
parser . add_option ( " -w " , " --wallet " , dest = " wallet_path " , help = " wallet path (default: electrum.dat) " )
2011-11-14 20:35:54 +01:00
parser . add_option ( " -a " , " --all " , action = " store_true " , dest = " show_all " , default = False , help = " show all addresses " )
parser . add_option ( " -b " , " --balance " , action = " store_true " , dest = " show_balance " , default = False , help = " show the balance at listed addresses " )
parser . add_option ( " -k " , " --keys " , action = " store_true " , dest = " show_keys " , default = False , help = " show the private keys of listed addresses " )
2011-12-18 22:49:33 +01:00
parser . add_option ( " -f " , " --fee " , dest = " tx_fee " , default = " 0.005 " , help = " set tx fee " )
2012-02-08 09:36:19 +01:00
parser . add_option ( " -s " , " --fromaddr " , dest = " from_addr " , default = None , help = " set source address for payto/mktx. if it isn ' t in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It ' s not saved in the wallet. " )
parser . add_option ( " -c " , " --changeaddr " , dest = " change_addr " , default = None , help = " set the change address for payto/mktx. default is a spare address, or the source address if it ' s not in the wallet " )
2011-11-14 20:35:54 +01:00
options , args = parser . parse_args ( )
2011-11-04 18:00:37 +01:00
2012-01-12 14:48:41 +01:00
interface = Interface ( )
wallet = Wallet ( interface )
2011-12-19 13:48:51 +01:00
wallet . set_path ( options . wallet_path )
2011-11-14 20:35:54 +01:00
2012-02-11 13:14:12 +01:00
cmd = args [ 0 ] if len ( args ) > 0 else ' gtk '
firstarg = args [ 1 ] if len ( args ) > 1 else ' '
if cmd in [ ' gtk ' , ' qt ' ] or re . match ( ' ^bitcoin: ' , cmd ) :
if cmd == ' qt ' :
import gui_qt as gui
else :
import gui
2012-02-09 15:39:25 +01:00
interface . get_servers ( )
2012-02-11 13:14:12 +01:00
try :
found = wallet . read ( )
if not found :
gui . restore_create_dialog ( wallet )
except BaseException , e :
2012-02-11 13:25:11 +01:00
gui . show_message ( e . message )
2012-02-11 13:14:12 +01:00
exit ( 1 )
2011-11-04 18:00:37 +01:00
gui = gui . BitcoinGUI ( wallet )
2012-02-08 13:37:14 +01:00
interface . start ( wallet )
2012-02-03 08:02:12 +01:00
2012-01-15 18:45:30 +01:00
if re . match ( ' ^bitcoin: ' , cmd ) :
2012-02-03 08:02:12 +01:00
2012-01-15 21:13:20 +01:00
o = cmd [ 8 : ] . split ( ' ? ' )
2012-02-03 15:45:41 +01:00
address = o [ 0 ]
2012-01-15 21:13:20 +01:00
if len ( o ) > 1 :
params = o [ 1 ] . split ( ' & ' )
else :
params = [ ]
2012-02-01 20:27:03 +01:00
2012-02-03 22:25:50 +01:00
amount = label = message = signature = identity = ' '
2012-01-15 18:45:30 +01:00
for p in params :
k , v = p . split ( ' = ' )
2012-02-01 20:27:03 +01:00
uv = urldecode ( v )
2012-02-03 08:02:12 +01:00
if k == ' amount ' : amount = uv
2012-02-03 22:25:50 +01:00
elif k == ' message ' : message = uv
2012-02-03 08:02:12 +01:00
elif k == ' label ' : label = uv
2012-02-03 11:48:09 +01:00
elif k == ' signature ' :
identity , signature = uv . split ( ' : ' )
cmd = cmd . replace ( ' & %s = %s ' % ( k , v ) , ' ' )
2012-02-03 08:02:12 +01:00
else :
print k , v
2012-02-03 22:25:50 +01:00
gui . set_send_tab ( address , amount , message , label , identity , signature , cmd )
2012-01-15 18:45:30 +01:00
2011-11-04 18:00:37 +01:00
gui . main ( )
2011-11-09 23:21:27 +01:00
wallet . save ( )
2011-11-10 09:34:27 +01:00
sys . exit ( 0 )
2011-11-04 18:00:37 +01:00
2012-01-15 18:45:30 +01:00
if cmd not in known_commands :
cmd = ' help '
2011-12-06 10:39:18 +01:00
if not wallet . read ( ) and cmd not in [ ' help ' , ' create ' ] :
2011-11-16 18:41:33 +03:00
print " Wallet file not found. "
print " Type ' electrum.py create ' to create a new wallet, or provide a path to a wallet with the -d option "
2011-11-16 18:26:06 +03:00
sys . exit ( 0 )
if cmd == ' create ' :
if wallet . read ( ) :
print " remove the existing wallet first! "
sys . exit ( 0 )
2011-11-29 10:26:47 +01:00
password = getpass . getpass ( " Password (hit return if you do not wish to encrypt your wallet): " )
if password :
password2 = getpass . getpass ( " Confirm password: " )
if password != password2 :
print " error "
sys . exit ( 1 )
2011-11-04 18:00:37 +01:00
else :
password = None
2012-02-08 13:37:14 +01:00
host = raw_input ( " server (default: %s ): " % interface . host )
port = raw_input ( " port (default: %d ): " % interface . port )
2012-02-06 07:48:52 +01:00
fee = raw_input ( " fee (default: %s ): " % ( str ( Decimal ( wallet . fee ) / 100000000 ) ) )
2011-11-06 11:13:58 +01:00
if fee : wallet . fee = float ( fee )
2012-02-08 13:37:14 +01:00
if host : interface . host = host
if port : interface . port = int ( port )
2011-11-06 11:13:58 +01:00
seed = raw_input ( " if you are restoring an existing wallet, enter the seed. otherwise just press enter: " )
2011-11-04 18:00:37 +01:00
wallet . gap_limit = 5
2011-11-06 11:13:58 +01:00
if seed :
2011-11-06 12:41:11 +01:00
wallet . seed = seed
2011-11-06 11:13:58 +01:00
gap = raw_input ( " gap limit (default 5): " )
if gap : wallet . gap_limit = int ( gap )
print " recovering wallet... "
2011-12-19 13:18:19 +01:00
wallet . synchronize ( )
if wallet . is_found ( ) :
wallet . fill_addressbook ( )
2011-11-06 11:13:58 +01:00
wallet . save ( )
2011-12-19 13:18:19 +01:00
print " recovery successful "
2011-11-06 11:13:58 +01:00
else :
print " no wallet found "
else :
wallet . new_seed ( None )
print " Your seed is " , wallet . seed
print " Please store it safely "
# generate first key
2011-12-18 23:02:59 +01:00
wallet . synchronize ( )
2011-11-04 18:00:37 +01:00
2011-11-12 00:07:41 +01:00
# check syntax
2012-02-08 09:36:19 +01:00
if cmd in [ ' payto ' , ' mktx ' ] :
2011-11-12 00:07:41 +01:00
try :
2012-02-08 09:36:19 +01:00
to_address = args [ 1 ]
amount = int ( 100000000 * Decimal ( args [ 2 ] ) )
2012-02-08 04:22:18 +01:00
change_addr = None
2012-02-08 09:36:19 +01:00
label = ' ' . join ( args [ 3 : ] )
2011-12-18 22:49:33 +01:00
if options . tx_fee :
options . tx_fee = int ( 100000000 * Decimal ( options . tx_fee ) )
2011-11-12 00:07:41 +01:00
except :
2011-11-16 18:12:13 +03:00
firstarg = cmd
cmd = ' help '
2011-11-12 00:07:41 +01:00
2011-11-14 20:35:54 +01:00
# open session
2012-02-06 18:13:33 +01:00
if cmd not in [ ' password ' , ' mktx ' , ' history ' , ' label ' , ' contacts ' , ' help ' , ' validateaddress ' , ' signmessage ' , ' verifymessage ' , ' eval ' ] :
2012-02-08 13:37:14 +01:00
interface . new_session ( wallet . all_addresses ( ) , wallet . electrum_version )
interface . update_wallet ( wallet )
2011-11-14 20:35:54 +01:00
wallet . save ( )
2012-02-11 06:48:44 +01:00
# check if --from_addr not in wallet (for mktx/payto)
is_temporary = False
from_addr = None
if options . from_addr :
from_addr = options . from_addr
if from_addr not in wallet . all_addresses ( ) :
is_temporary = True
2011-11-14 20:35:54 +01:00
# commands needing password
2012-02-08 09:36:19 +01:00
if cmd in [ ' payto ' , ' password ' , ' mktx ' , ' seed ' , ' import ' , ' signmessage ' ] or ( cmd == ' addresses ' and options . show_keys ) :
2012-02-11 06:48:44 +01:00
password = getpass . getpass ( ' Password: ' ) if wallet . use_encryption and not is_temporary else None
2011-12-20 14:22:31 +01:00
# check password
2011-12-20 12:37:48 +01:00
try :
2011-12-20 14:22:31 +01:00
wallet . pw_decode ( wallet . seed , password )
2011-12-20 12:37:48 +01:00
except :
print " invalid password "
exit ( 1 )
2011-12-20 14:22:31 +01:00
if cmd == ' import ' :
2011-12-20 12:37:48 +01:00
keypair = args [ 1 ]
if wallet . import_key ( keypair , password ) :
print " keypair imported "
else :
print " error "
wallet . save ( )
2011-11-16 18:12:13 +03:00
if cmd == ' help ' :
cmd2 = firstarg
if cmd2 not in known_commands :
print " known commands: " , ' , ' . join ( known_commands )
print " help <command> shows the help on a specific command "
elif cmd2 == ' balance ' :
2012-01-16 02:02:48 +02:00
print " Display the balance of your wallet or a specific address. The address does not have to be a owned address (you know the private key). "
print " syntax: balance [<address>] "
2011-11-16 18:12:13 +03:00
elif cmd2 == ' contacts ' :
print " show your list of contacts "
elif cmd2 == ' payto ' :
print " payto <recipient> <amount> [label] "
print " create and broadcast a transaction. "
print " <recipient> can be a bitcoin address or a label "
2012-02-10 13:23:39 +01:00
print " options: --fee, --fromaddr, --changeaddr "
2011-11-16 18:12:13 +03:00
elif cmd2 == ' sendtx ' :
print " sendtx <tx> "
print " broadcast a transaction to the network. <tx> must be in hexadecimal "
elif cmd2 == ' password ' :
print " change your password "
elif cmd2 == ' newaddress ' :
print " create a new receiving address. password is needed. "
elif cmd2 == ' addresses ' :
print " show your list of addresses. options: -a, -k, -b "
elif cmd2 == ' history ' :
print " show the transaction history "
elif cmd2 == ' label ' :
print " assign a label to an item "
2012-02-11 13:14:12 +01:00
elif cmd2 == ' gtk ' :
2011-11-16 18:12:13 +03:00
print " start the GUI "
elif cmd2 == ' mktx ' :
print " create a signed transaction. password protected "
print " syntax: mktx <recipient> <amount> [label] "
2012-02-10 13:23:39 +01:00
print " options: --fee, --fromaddr, --changeaddr "
2011-11-16 18:12:13 +03:00
elif cmd2 == ' seed ' :
print " show generation seed of your wallet. password protected. "
2012-02-06 18:13:33 +01:00
elif cmd2 == ' eval ' :
2012-02-08 17:11:20 +01:00
print " Run python eval() on an object \n Syntax: eval <expression> \n Example: eval \" wallet.aliases \" "
2011-11-16 18:12:13 +03:00
elif cmd == ' seed ' :
2011-11-14 20:35:54 +01:00
import mnemonic
2011-11-18 13:07:28 +01:00
seed = wallet . pw_decode ( wallet . seed , password )
print seed , ' " ' + ' ' . join ( mnemonic . mn_encode ( seed ) ) + ' " '
2011-11-14 20:35:54 +01:00
2011-11-17 01:55:29 +01:00
elif cmd == ' validateaddress ' :
addr = args [ 1 ]
print wallet . is_valid ( addr )
2011-11-16 17:16:36 +03:00
elif cmd == ' balance ' :
2012-01-16 02:02:48 +02:00
try :
addrs = args [ 1 : ]
except :
pass
if addrs == [ ] :
c , u = wallet . get_balance ( )
if u :
2012-02-06 07:48:52 +01:00
print Decimal ( c ) / 100000000 , Decimal ( u ) / 100000000
2012-01-16 02:02:48 +02:00
else :
2012-02-06 07:48:52 +01:00
print Decimal ( c ) / 100000000
2011-11-04 18:00:37 +01:00
else :
2012-01-16 02:02:48 +02:00
for addr in addrs :
c , u = wallet . get_addr_balance ( addr )
if u :
2012-02-06 07:48:52 +01:00
print " %s %s , %s " % ( addr , str ( Decimal ( c ) / 100000000 ) , str ( Decimal ( u ) / 100000000 ) )
2012-01-16 02:02:48 +02:00
else :
2012-02-06 07:48:52 +01:00
print " %s %s " % ( addr , str ( Decimal ( c ) / 100000000 ) )
2011-11-04 18:00:37 +01:00
2011-11-14 20:35:54 +01:00
elif cmd in [ ' contacts ' ] :
2011-11-12 00:07:41 +01:00
for addr in wallet . addressbook :
print addr , " " , wallet . labels . get ( addr )
2012-02-06 18:13:33 +01:00
elif cmd == ' eval ' :
print eval ( args [ 1 ] )
2012-02-06 18:55:25 +01:00
wallet . save ( )
2012-02-03 17:38:43 +01:00
2011-11-14 20:35:54 +01:00
elif cmd in [ ' addresses ' ] :
2011-12-18 22:49:33 +01:00
for addr in wallet . all_addresses ( ) :
2011-11-14 20:35:54 +01:00
if options . show_all or not wallet . is_change ( addr ) :
2011-12-21 17:56:26 +01:00
label = wallet . labels . get ( addr )
_type = ' '
if wallet . is_change ( addr ) : _type = " [change] "
if addr in wallet . imported_keys . keys ( ) : _type = " [imported] "
2011-11-04 18:00:37 +01:00
if label is None : label = ' '
2011-11-14 20:35:54 +01:00
if options . show_balance :
2011-12-21 17:58:14 +01:00
h = wallet . history . get ( addr , [ ] )
2011-11-14 20:35:54 +01:00
ni = no = 0
for item in h :
if item [ ' is_in ' ] : ni + = 1
else : no + = 1
2012-02-06 07:48:52 +01:00
b = " %d %d %s " % ( no , ni , str ( Decimal ( wallet . get_addr_balance ( addr ) [ 0 ] ) / 100000000 ) )
2011-11-14 20:35:54 +01:00
else : b = ' '
2011-12-20 14:07:37 +01:00
if options . show_keys :
pk = wallet . get_private_key2 ( addr , password )
addr = addr + ' : ' + SecretToASecret ( pk )
2011-12-21 17:56:26 +01:00
print addr , b , _type , label
2011-11-04 18:00:37 +01:00
if cmd == ' history ' :
lines = wallet . get_tx_history ( )
b = 0
for line in lines :
import datetime
2012-02-06 07:48:52 +01:00
v = line [ ' value ' ]
2011-11-04 18:00:37 +01:00
b + = v
try :
time_str = datetime . datetime . fromtimestamp ( line [ ' nTime ' ] )
except :
print line [ ' nTime ' ]
time_str = ' pending '
label = line . get ( ' label ' )
if not label : label = line [ ' tx_hash ' ]
else : label = label + ' ' * ( 64 - len ( label ) )
2012-02-06 07:48:52 +01:00
print time_str , " " + label + " " + format_satoshis ( v ) + " " + format_satoshis ( b )
print " # balance: " , format_satoshis ( b )
2011-11-04 18:00:37 +01:00
elif cmd == ' label ' :
try :
2011-11-14 20:35:54 +01:00
tx = args [ 1 ]
label = ' ' . join ( args [ 2 : ] )
2011-11-04 18:00:37 +01:00
except :
print " syntax: label <tx_hash> <text> "
2011-11-10 09:34:27 +01:00
sys . exit ( 1 )
2011-11-04 18:00:37 +01:00
wallet . labels [ tx ] = label
wallet . save ( )
2012-02-08 09:36:19 +01:00
elif cmd in [ ' payto ' , ' mktx ' ] :
2012-02-11 06:48:44 +01:00
if from_addr and is_temporary :
if from_addr . find ( " : " ) == - 1 :
keypair = from_addr + " : " + getpass . getpass ( ' Private key: ' )
else :
keypair = from_addr
from_addr = keypair . split ( ' : ' ) [ 0 ]
if not wallet . import_key ( keypair , password ) :
print " invalid key pair "
exit ( 1 )
wallet . history [ from_addr ] = interface . retrieve_history ( from_addr )
wallet . update_tx_history ( )
change_addr = from_addr
2012-02-10 13:23:39 +01:00
2012-02-08 09:36:19 +01:00
if options . change_addr :
change_addr = options . change_addr
2012-02-10 13:23:39 +01:00
2011-11-12 00:07:41 +01:00
for k , v in wallet . labels . items ( ) :
if v == to_address :
to_address = k
2011-11-17 01:55:29 +01:00
print " alias " , to_address
2011-11-12 00:07:41 +01:00
break
2012-02-08 04:22:18 +01:00
if change_addr and v == change_addr :
change_addr = k
2011-12-18 22:49:33 +01:00
try :
2012-02-08 04:22:18 +01:00
tx = wallet . mktx ( to_address , amount , label , password ,
2012-02-10 13:23:39 +01:00
fee = options . tx_fee , change_addr = change_addr , from_addr = from_addr )
except :
import traceback
traceback . print_exc ( file = sys . stdout )
2011-12-18 22:49:33 +01:00
tx = None
2012-02-08 09:36:19 +01:00
if tx and cmd == ' payto ' :
2011-11-16 17:16:36 +03:00
r , h = wallet . sendtx ( tx )
print h
else :
2011-12-18 22:49:33 +01:00
print tx
2011-11-16 17:16:36 +03:00
2012-02-10 13:23:39 +01:00
if is_temporary :
wallet . imported_keys . pop ( from_addr )
2012-02-11 05:50:07 +01:00
del ( wallet . history [ from_addr ] )
2012-02-10 13:23:39 +01:00
wallet . save ( )
2011-12-15 15:41:50 +01:00
elif cmd == ' sendtx ' :
2011-11-16 17:16:36 +03:00
tx = args [ 1 ]
r , h = wallet . sendtx ( tx )
print h
2011-11-04 18:00:37 +01:00
2011-11-14 20:35:54 +01:00
elif cmd == ' newaddress ' :
2011-12-15 15:41:50 +01:00
s , a = wallet . get_new_address ( )
2011-12-08 01:42:55 +01:00
print a
2011-11-04 18:00:37 +01:00
elif cmd == ' password ' :
try :
2011-11-05 15:06:43 +01:00
seed = wallet . pw_decode ( wallet . seed , password )
2011-11-04 18:00:37 +01:00
except :
print " sorry "
2011-11-10 09:34:27 +01:00
sys . exit ( 1 )
2011-11-04 18:00:37 +01:00
new_password = getpass . getpass ( ' New password: ' )
if new_password == getpass . getpass ( ' Confirm new password: ' ) :
wallet . use_encryption = ( new_password != ' ' )
2011-11-05 15:06:43 +01:00
wallet . seed = wallet . pw_encode ( seed , new_password )
2011-12-20 12:37:48 +01:00
for k in wallet . imported_keys . keys ( ) :
a = wallet . imported_keys [ k ]
b = wallet . pw_decode ( a , password )
c = wallet . pw_encode ( b , new_password )
wallet . imported_keys [ k ] = c
2011-11-04 18:00:37 +01:00
wallet . save ( )
else :
print " error: mismatch "
2012-02-01 20:27:03 +01:00
elif cmd == ' signmessage ' :
address , message = args [ 1 : 3 ]
print wallet . sign_message ( address , message , password )
elif cmd == ' verifymessage ' :
address , signature , message = args [ 1 : 4 ]
2012-02-03 11:48:09 +01:00
try :
wallet . verify_message ( address , signature , message )
print True
except :
print False
2012-02-01 20:27:03 +01:00