move 'addresses' command
[electrum-nvc.git] / lib / commands.py
1 #!/usr/bin/env python
2 #
3 # Electrum - lightweight Bitcoin client
4 # Copyright (C) 2011 thomasv@gitorious
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19
20 from util import *
21 from bitcoin import *
22 from decimal import Decimal
23 import bitcoin
24
25 protected_commands = ['payto', 'password', 'mktx', 'get_seed', 'importprivkey','signmessage', 'signrawtransaction', 'dumpprivkey', 'dumpprivkeys' ]
26
27 class Commands:
28
29     def __init__(self, wallet, interface):
30         self.wallet = wallet
31         self.interface = interface
32
33     def _run(self, method, args, password_getter):
34         if method in protected_commands:
35             self.password = apply(password_getter,())
36         f = eval('self.'+method)
37         apply(f,args)
38         self.password = None
39
40     def get_history(self, addr):
41         h = self.wallet.get_history(addr)
42         if h is None: h = self.wallet.interface.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
43         print_json(h)
44
45     def listunspent(self):
46         l = self.wallet.get_unspent_coins()
47         for i in l: i["value"] = i["value"]*1e-8
48         print_json(l)
49
50     def createrawtransaction(self, inputs, outputs):
51         # convert to own format
52         for i in inputs:
53             i['tx_hash'] = i['txid']
54             i['index'] = i['vout']
55         outputs = map(lambda x: (x[0],int(1e8*x[1])), outputs.items())
56         tx = Transaction.from_io(inputs, outputs)
57         print_msg( tx )
58
59     def signrawtransaction(self, raw_tx, input_info, private_keys):
60         tx = Transaction(raw_tx)
61         unspent_coins = self.wallet.get_unspent_coins()
62
63         # convert private_keys to dict 
64         pk = {}
65         for sec in private_keys:
66             address = bitcoin.address_from_private_key(sec)
67             pk[address] = sec
68         private_keys = pk
69
70         for txin in tx.inputs:
71             # convert to own format
72             txin['tx_hash'] = txin['prevout_hash']
73             txin['index'] = txin['prevout_n']
74
75             for item in input_info:
76                 if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']:
77                     txin['raw_output_script'] = item['scriptPubKey']
78                     txin['redeemScript'] = item.get('redeemScript')
79                     txin['electrumKeyID'] = item.get('electrumKeyID')
80                     break
81             else:
82                 for item in unspent_coins:
83                     if txin['tx_hash'] == item['tx_hash'] and txin['index'] == item['index']:
84                         txin['raw_output_script'] = item['raw_output_script']
85                         break
86                 else:
87                     # if neither, we might want to get it from the server..
88                     raise
89
90             # find the address:
91             import deserialize
92             if txin.get('electrumKeyID'):
93                 n, for_change = txin.get('electrumKeyID')
94                 sec = wallet.sequence.get_private_key(n, for_change, seed)
95                 address = bitcoin.address_from_private_key(sec)
96                 txin['address'] = address
97                 private_keys[address] = sec
98
99             elif txin.get("redeemScript"):
100                 txin['address'] = bitcoin.hash_160_to_bc_address(bitcoin.hash_160(txin.get("redeemScript").decode('hex')), 5)
101
102             elif txin.get("raw_output_script"):
103                 addr = deserialize.get_address_from_output_script(txin.get("raw_output_script").decode('hex'))
104                 sec = wallet.get_private_key(addr, self.password)
105                 if sec: 
106                     private_keys[addr] = sec
107                     txin['address'] = addr
108
109         tx.sign( private_keys )
110         print_json({ "hex":str(tx),"complete":tx.is_complete})
111
112     def decoderawtransaction(self, raw):
113         tx = Transaction(raw)
114         print_json( tx.deserialize() )
115
116     def sendrawtransaction(self, raw):
117         tx = Transaction(raw)
118         r, h = wallet.sendtx( tx )
119         print_msg(h)
120
121     def createmultisig(self, num, pubkeys):
122         assert isinstance(pubkeys, list)
123         print_json( Transaction.multisig_script(pubkeys, num) )
124     
125     def freeze(self,addr):
126         print_msg(self.wallet.freeze(addr))
127         
128     def unfreeze(self,addr):
129         print_msg(self.wallet.unfreeze(addr))
130
131     def prioritize(self, addr):
132         print_msg(self.wallet.prioritize(addr))
133
134     def unprioritize(self, addr):
135         print_msg(self.wallet.unprioritize(addr))
136
137     def dumpprivkey(self, addr):
138         print_msg( self.wallet.get_private_key(addr, self.password) )
139
140     def dumpprivkeys(self, addresses):
141         print_json( self.wallet.get_private_keys(addresses, self.password) )
142
143
144     def validateaddress(self,addr):
145         is_valid = self.wallet.is_valid(addr)
146         out = { 'isvalid':is_valid }
147         if is_valid:
148             is_mine = self.wallet.is_mine(addr)
149             out['address'] = addr
150             out['ismine'] = is_mine
151             if is_mine:
152                 out['pubkey'] = self.wallet.get_public_key(addr)
153             
154         print_json(out)
155
156         
157     def balance(self, addresses = []):
158         if addresses == []:
159             c, u = self.wallet.get_balance()
160             if u:
161                 print_msg(Decimal( c ) / 100000000 , Decimal( u ) / 100000000)
162             else:
163                 print_msg(Decimal( c ) / 100000000)
164         else:
165             for addr in addresses:
166                 c, u = wallet.get_addr_balance(addr)
167                 if u:
168                     print_msg("%s %s, %s" % (addr, str(Decimal(c)/100000000), str(Decimal(u)/100000000)))
169                 else:
170                     print_msg("%s %s" % (addr, str(Decimal(c)/100000000)))
171
172
173     def get_seed(self):
174         import mnemonic
175         seed = self.wallet.decode_seed(self.password)
176         print_msg(seed + ' "' + ' '.join(mnemonic.mn_encode(seed)) + '"')
177
178     def importprivkey(self, sec):
179         try:
180             addr = wallet.import_key(sec,self.password)
181             wallet.save()
182             print_msg("Keypair imported: ", addr)
183         except BaseException as e:
184             print_msg("Error: Keypair import failed: " + str(e))
185
186
187     def sign_message(self, address, message):
188         print_msg(self.wallet.sign_message(address, message, self.password))
189
190
191     def verify_message(self, address, signature, message):
192         try:
193             EC_KEY.verify_message(address, signature, message)
194             print_msg(True)
195         except BaseException as e:
196             print_error("Verification error: {0}".format(e))
197             print_msg(False)
198
199
200     def _mktx(self, to_address, amount, fee = None, change_addr = None, from_addr = None):
201         for k, v in self.wallet.labels.items():
202             if v == to_address:
203                 to_address = k
204                 print_msg("alias", to_address)
205                 break
206             if change_addr and v == change_addr:
207                 change_addr = k
208
209         amount = int(10000000*amount)
210         if fee: fee = int(10000000*fee)
211         return self.wallet.mktx( [(to_address, amount)], self.password, fee , change_addr, from_addr)
212
213
214     def mktx(self, to_address, amount, fee = None, change_addr = None, from_addr = None):
215         tx = self._mktx(to_address, amount, fee, change_addr, from_addr)
216         out = {"hex":str(tx), "complete":tx.is_complete}
217         if not tx.is_complete: 
218             out['input_info'] = repr(tx.input_info).replace(' ','')
219         print_json(out)
220
221
222     def payto(self, to_address, amount, fee = None, change_addr = None, from_addr = None):
223         tx = self._mktx(to_address, amount, fee, change_addr, from_addr)
224         r, h = wallet.sendtx( tx )
225         print_msg(h)
226
227
228     def history(self):
229         import datetime
230         balance = 0
231         for item in self.wallet.get_tx_history():
232             tx_hash, conf, is_mine, value, fee, balance, timestamp = item
233             try:
234                 time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
235             except:
236                 time_str = "----"
237
238             label, is_default_label = self.wallet.get_label(tx_hash)
239             if not label: label = tx_hash
240             else: label = label + ' '*(64 - len(label) )
241
242             print_msg("%17s"%time_str, "  " + label + "  " + format_satoshis(value)+ "  "+ format_satoshis(balance))
243         print_msg("# balance: ", format_satoshis(balance))
244
245
246     def setlabel(self, tx, label):
247         self.wallet.labels[tx] = label
248         self.wallet.save()
249             
250
251     def contacts(self):
252         c = {}
253         for addr in self.wallet.addressbook:
254             c[addr] = self.wallet.labels.get(addr)
255         print_json(c)
256
257
258     def addresses(self, show_all):
259         for addr in self.wallet.all_addresses():
260             if show_all or not self.wallet.is_change(addr):
261
262                 flags = self.wallet.get_address_flags(addr)
263                 label = self.wallet.labels.get(addr,'')
264                 if label: label = "\"%s\""%label
265                 b = format_satoshis(self.wallet.get_addr_balance(addr)[0])
266                 m_addr = "%34s"%addr
267                 print_msg(flags, m_addr, b, label)
268