forked from dfkthf125/api-v1-client-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwallet.py
209 lines (161 loc) · 7.7 KB
/
wallet.py
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""This module corresponds to functionality documented
at https://blockchain.info/api/blockchain_wallet_api
"""
import json
from . import util
from .exceptions import *
class Wallet:
"""The :class:`Wallet` class mirrors operations listed on the wallet API page.
It needs to be initialized on a per-wallet basis and will cache the wallet
identitifer, password, second password and API key (if provided).
"""
def __init__(self, identifier, password, service_url, second_password=None, api_code=None):
"""Initializes a wallet object.
:param str identifier: wallet identifier (GUID)
:param str password : decryption password
:param str service_url : URL to an instance of service-my-wallet-v3 (with trailing slash)
:param str second_password: second password (optional)
:param str api_code: Blockchain.info API code
"""
self.identifier = identifier
self.password = password
self.service_url = service_url
self.second_password = second_password
self.api_code = api_code
def send(self, to, amount, from_address=None, fee=None):
"""Send bitcoin from your wallet to a single address.
:param str to: recipient bitcoin address
:param int amount: amount to send (in satoshi)
:param str from_address: specific address to send from (optional)
:param int fee: transaction fee in satoshi. Must be greater than the default
fee (optional).
:return: an instance of :class:`PaymentResponse` class
"""
recipient = {to: amount}
return self.send_many(recipient, from_address, fee)
def send_many(self, recipients, from_address=None, fee=None):
"""Send bitcoin from your wallet to multiple addresses.
:param dictionary recipients: dictionary with the structure of 'address':amount
:param str from_address: specific address to send from (optional)
:param int fee: transaction fee in satoshi. Must be greater than the default
fee (optional).
:return: an instance of :class:`PaymentResponse` class
"""
params = self.build_basic_request(read_only=False)
if len(recipients) == 1:
to_address, amount = recipients.popitem()
params['to'] = to_address
params['amount'] = amount
method = 'payment'
else:
params['recipients'] = json.dumps(recipients)
method = 'sendmany'
if from_address is not None:
params['from'] = from_address
if fee is not None:
params['fee'] = fee
response = util.call_api("merchant/{0}/{1}".format(self.identifier, method), params,
base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
payment_response = PaymentResponse(json_response['message'],
json_response['tx_hash'],
json_response.get('notice'))
return payment_response
def get_balance(self):
"""Fetch the wallet balance. Includes unconfirmed transactions
and possibly double spends.
:return: wallet balance in satoshi
"""
response = util.call_api("merchant/{0}/balance".format(self.identifier), self.build_basic_request(),
base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
return json_response.get('balance')
def list_addresses(self):
"""List all active addresses in the wallet.
:return: an array of :class:`Address` objects
"""
params = self.build_basic_request()
response = util.call_api("merchant/{0}/list".format(self.identifier), params, base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
addresses = []
for a in json_response['addresses']:
address = Address(a['balance'], a['address'], a.get('label'), a['total_received'])
addresses.append(address)
return addresses
def get_address(self, address):
"""Retrieve an address from the wallet.
:param str address: address in the wallet to look up
:return: an instance of :class:`Address` class
"""
params = self.build_basic_request()
params['address'] = address
response = util.call_api("merchant/{0}/address_balance".format(self.identifier), params,
base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
return Address(json_response['balance'],
json_response['address'],
None,
json_response['total_received'])
def new_address(self, label=None):
"""Generate a new address and add it to the wallet.
:param str label: label to attach to this address (optional)
:return: an instance of :class:`Address` class
"""
params = self.build_basic_request()
if label is not None:
params['label'] = label
response = util.call_api("merchant/{0}/new_address".format(self.identifier), params, base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
return Address(0, json_response['address'], json_response.get('label'), 0)
def archive_address(self, address):
"""Archive an address.
:param str address: address to archive
:return: string representation of the archived address
"""
params = self.build_basic_request()
params['address'] = address
response = util.call_api("merchant/{0}/archive_address".format(self.identifier), params,
base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
return json_response['archived']
def unarchive_address(self, address):
"""Unarchive an address.
:param str address: address to unarchive
:return: string representation of the unarchived address
"""
params = self.build_basic_request()
params['address'] = address
response = util.call_api("merchant/{0}/unarchive_address".format(self.identifier), params,
base_url=self.service_url)
json_response = json.loads(response)
self.parse_error(json_response)
return json_response['active']
def build_basic_request(self, read_only=True):
params = {'password': self.password}
if self.second_password is not None and read_only is False:
params['second_password'] = self.second_password
if self.api_code is not None:
params['api_code'] = self.api_code
return params
@staticmethod
def parse_error(json_response):
error = json_response.get('error')
if error is not None:
raise APIException(error, 0)
class PaymentResponse:
def __init__(self, message, tx_hash, notice):
self.message = message
self.tx_hash = tx_hash
self.notice = notice
class Address:
def __init__(self, balance, address, label, total_received):
self.balance = balance
self.address = address
self.label = label
self.total_received = total_received