-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathLocalBitcoin.py
More file actions
300 lines (254 loc) · 11.6 KB
/
LocalBitcoin.py
File metadata and controls
300 lines (254 loc) · 11.6 KB
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
import hmac
import json
import urllib.parse
import hashlib
import requests
from datetime import datetime
class LocalBitcoin:
baseurl = 'https://localbitcoins.com'
def __init__(self, hmac_auth_key, hmac_auth_secret, debug = False):
self.hmac_auth_key = hmac_auth_key
self.hmac_auth_secret = hmac_auth_secret
self.debug = debug
"""
Returns public user profile information
"""
def getAccountInfo(self, username):
return self.sendRequest('/api/account_info/' + username + '/', '', 'get')
"""
Return the information of the currently logged in user (the owner of authentication token).
"""
def getMyself(self):
return self.sendRequest('/api/myself/', '', 'get')
"""
Checks the given PIN code against the user's currently active PIN code.
You can use this method to ensure the person using the session is the legitimate user.
"""
def checkPinCode(self, code):
return self.sendRequest('/api/pincode/', {'code': code}, 'post')
"""
Return open and active contacts
"""
def getDashboard(self):
return self.sendRequest('/api/dashboard/', '', 'get')
"""
Return released (successful) contacts
"""
def getDashboardReleased(self):
return self.sendRequest('/api/dashboard/released/', '', 'get')
"""
Return canceled contacts
"""
def getDashboardCanceled(self):
return self.sendRequest('/api/dashboard/canceled/', '', 'get')
"""
Return closed contacts, both released and canceled
"""
def getDashboardClosed(self):
return self.sendRequest('/api/dashboard/closed/', '', 'get')
"""
Releases the escrow of contact specified by ID {contact_id}.
On success there's a complimentary message on the data key.
"""
def contactRelease(self, contact_id):
return self.sendRequest('/api/contact_release/' + contact_id + '/', '', 'post')
"""
Releases the escrow of contact specified by ID {contact_id}.
On success there's a complimentary message on the data key.
"""
def contactReleasePin(self, contact_id, pincode):
return self.sendRequest('/api/contact_release_pin/' + contact_id + '/', {'pincode': pincode}, 'post')
"""
Reads all messaging from the contact. Messages are on the message_list key.
On success there's a complimentary message on the data key.
attachment_* fields exist only if there is an attachment.
"""
def getContactMessages(self, contact_id):
return self.sendRequest('/api/contact_messages/' + contact_id + '/', '', 'get')
"""
Marks a contact as paid.
It is recommended to access this API through /api/online_buy_contacts/ entries' action key.
"""
def markContactAsPaid(self, contact_id):
return self.sendRequest('/api/contact_mark_as_paid/' + contact_id + '/', '', 'get')
"""
Post a message to contact
"""
def postMessageToContact(self, contact_id, message):
return self.sendRequest('/api/contact_message_post/' + contact_id + '/', {'msg': message}, 'post')
"""
Starts a dispute with the contact, if possible.
You can provide a short description using topic. This helps support to deal with the problem.
"""
def startDispute(self, contact_id, topic = None):
topic = ''
if topic != None:
topic = {'topic': topic}
return self.sendRequest('/api/contact_dispute/' + contact_id + '/', topic, 'post')
"""
Cancels the contact, if possible
"""
def cancelContact(self, contact_id):
return self.sendRequest('/api/contact_cancel/' + contact_id + '/', '', 'post')
"""
Attempts to fund an unfunded local contact from the seller's wallet.
"""
def fundContact(self, contact_id):
return self.sendRequest('/api/contact_fund/' + contact_id + '/', '', 'post')
"""
Attempts to create a contact to trade bitcoins.
Amount is a number in the advertisement's fiat currency.
Returns the API URL to the newly created contact at actions.contact_url.
Whether the contact was able to be funded automatically is indicated at data.funded.
Only non-floating LOCAL_SELL may return unfunded, all other trade types either fund or fail.
"""
def createContact(self, contact_id, ammount, message = None):
post = ''
if message == None:
post = {'ammount': ammount}
else:
post = {'ammount': ammount, 'message': message}
return self.sendRequest('/api/contact_create/' + contact_id + '/', post, 'post')
"""
Gets information about a single contact you are involved in. Same fields as in /api/contacts/.
"""
def getContactInfo(self, contact_id):
return self.sendRequest('/api/contact_info/' + contact_id + '/', '', 'get')
"""
contacts is a comma-separated list of contact IDs that you want to access in bulk.
The token owner needs to be either a buyer or seller in the contacts, contacts that do not pass this check are simply not returned.
A maximum of 50 contacts can be requested at a time.
The contacts are not returned in any particular order.
"""
def getContactsInfo(self, contacts):
return self.sendRequest('/api/contact_info/', {'contacts': contacts}, 'get')
"""
Returns maximum of 50 newest trade messages.
Messages are ordered by sending time, and the newest one is first.
The list has same format as /api/contact_messages/, but each message has also contact_id field.
"""
def getRecentMessages(self):
return self.sendRequest('/api/recent_messages/', '', 'get')
"""
Gives feedback to user.
Possible feedback values are: trust, positive, neutral, block, block_without_feedback as strings.
You may also set feedback message field with few exceptions. Feedback block_without_feedback clears the message and with block the message is mandatory.
"""
def postFeedbackToUser(self, username, feedback, message = None):
post = {'feedback': feedback}
if message != None:
post = {'feedback': feedback, 'msg': message}
return self.sendRequest('/api/feedback/' + username + '/', post, 'post')
"""
Gets information about the token owner's wallet balance.
"""
def getWallet(self):
return self.sendRequest('/api/wallet/', '', 'get')
"""
Same as /api/wallet/ above, but only returns the message, receiving_address_list and total fields.
(There's also a receiving_address_count but it is always 1: only the latest receiving address is ever returned by this call.)
Use this instead if you don't care about transactions at the moment.
"""
def getWalletBallance(self):
return self.sendRequest('/api/wallet-balance/', '', 'get')
"""
Sends amount bitcoins from the token owner's wallet to address.
Note that this API requires its own API permission called Money.
On success, this API returns just a message indicating success.
It is highly recommended to minimize the lifetime of access tokens with the money permission.
Call /api/logout/ to make the current token expire instantly.
"""
def walletSend(self, ammount, address):
return self.sendRequest('/api/wallet-send/', {'ammount': ammount, 'address': address}, 'post')
"""
As above, but needs the token owner's active PIN code to succeed.
Look before you leap. You can check if a PIN code is valid without attempting a send with /api/pincode/.
Security concern: To get any security beyond the above API, do not retain the PIN code beyond a reasonable user session, a few minutes at most.
If you are planning to save the PIN code anyway, please save some headache and get the real no-pin-required money permission instead.
"""
def walletSendWithPin(self, ammount, address, pincode):
return self.sendRequest('/api/wallet-send-pin/', {'ammount': ammount, 'address': address, 'pincode': pincode}, 'post')
"""
Gets an unused receiving address for the token owner's wallet, its address given in the address key of the response.
Note that this API may keep returning the same (unused) address if called repeatedly.
"""
def getWalletAddress(self):
return self.sendRequest('/api/wallet-addr/', '', 'post')
"""
Expires the current access token immediately.
To get a new token afterwards, public apps will need to reauthenticate, confidential apps can turn in a refresh token.
"""
def logout(self):
return self.sendRequest('/api/logout/', '', 'post')
"""
Lists the token owner's all ads on the data key ad_list, optionally filtered. If there's a lot of ads, the listing will be paginated.
Refer to the ad editing pages for the field meanings. List item structure is like so:
"""
def getOwnAds(self):
return self.sendRequest('/api/ads/', '', 'post')
"""
List available country codes in LocalBitcoin
"""
def getCountryCodes(self):
return self.sendRequest('/api/countrycodes/', '', 'get')
"""
List payment methods
"""
def getPaymentMethods(self, countryCode):
return self.sendRequest('/api/payment_methods/' + countryCode + '/', '', 'get')
"""
Lists buy Bitcoin online ads
"""
def getOnlineBuyAds(self, countryCode, countryName, paymentMethod = None):
endpoint = '/buy-bitcoins-online/' + countryCode + '/' + countryName
if (paymentMethod):
endpoint += '/' + paymentMethod
endpoint += '/.json'
return self.sendRequest(endpoint, '', 'get')
"""
Lists sell Bitcoin online ads
"""
def getOnlineSellAds(self, countryCode, countryName, paymentMethod=None):
endpoint = '/sell-bitcoins-online/' + countryCode + '/' + countryName
if (paymentMethod):
endpoint += '/' + paymentMethod
endpoint += '/.json'
return self.sendRequest(endpoint, '', 'get')
"""
Calculates the current price for bitcoin with the specified equation.
"""
def getBitcoinPrice(self, equation):
return self.sendRequest('/api/equation/' + equation, '', 'get')
"""
Update equation of an advertisement.
"""
def updateAdsEquation(self, ad_id, equation):
return self.sendRequest('/api/ad-equation/' + str(ad_id) + '/', {'price_equation': equation}, 'post')
def sendRequest(self, endpoint, params, method):
params_encoded = ''
if params != '':
params_encoded = urllib.parse.urlencode(params)
if method == 'get':
params_encoded = '?' + params_encoded
now = datetime.utcnow()
epoch = datetime.utcfromtimestamp(0)
delta = now - epoch
nonce = int(delta.total_seconds() * 1000)
message = str(nonce) + self.hmac_auth_key + endpoint + params_encoded
message = message.encode('utf-8')
# signature = hmac.new(self.hmac_auth_secret, msg = message, digestmod = hashlib.sha256).hexdigest().upper()
signature = hmac.new(bytearray(self.hmac_auth_secret, 'utf-8'), msg=message, digestmod=hashlib.sha256).hexdigest().upper()
headers = {}
headers['Apiauth-key'] = self.hmac_auth_key
headers['Apiauth-Nonce'] = str(nonce)
headers['Apiauth-Signature'] = signature
if method == 'get':
response = requests.get(self.baseurl + endpoint, headers = headers, params = params)
else:
response = requests.post(self.baseurl + endpoint, headers = headers, data = params)
if self.debug == True:
print('REQUEST: ' + self.baseurl + endpoint)
print('PARAMS: ' + str(params))
print('METHOD: ' + method)
print('RESPONSE: ' + response.text)
return json.loads(response.text)['data']