0

Writing a bot for a personal project, and the Bittrex api refuses to validate my content hash. I've tried everything I can think of and all the suggestions from similar questions, but nothing has worked so far. Tried hashing 'None', tried a blank string, tried the currency symbol, tried the whole uri, tried the command & balance, tried a few other things that also didn't work. Reformatted the request a few times (bytes/string/dict), still nothing.

Documentation says to hash the request body (which seems synonymous with payload in similar questions about making transactions through the api), but it's a simple get/chcek balance request with no payload.

Problem is, I get a 'BITTREX ERROR: INVALID CONTENT HASH' response when I run it.

Any help would be greatly appreciated, this feels like a simple problem but it's been frustrating the hell out of me. I am very new to python, but the rest of the bot went very well, which makes it extra frustrating that I can't hook it up to my account :/

import hashlib
import hmac
import json
import os
import time
import requests
import sys

# Base Variables
Base_Url = 'https://api.bittrex.com/v3'
APIkey = os.environ.get('B_Key')
secret = os.environ.get('S_B_Key')
timestamp = str(int(time.time() * 1000))
command = 'balances'
method = 'GET'
currency = 'USD'
uri = Base_Url + '/' + command + '/' + currency

payload = ''
print(payload)  # Payload Check

#  Hashes Payload
content = json.dumps(payload, separators=(',', ':'))
content_hash = hashlib.sha512(bytes(json.dumps(content), "utf-8")).hexdigest()
print(content_hash)

#  Presign
presign = (timestamp + uri + method + str(content_hash) + '')
print(presign)

# Create Signature
message = f'{timestamp}{uri}{method}{content_hash}'
sign = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), 
hashlib.sha512).hexdigest()

print(sign)

headers = {
    'Api-Key': APIkey,
    'Api-Timestamp': timestamp,
    'Api-Signature': sign,
    'Api-Content-Hash': content_hash
    }
print(headers)

req = requests.get(uri, json=payload, headers=headers)
tracker_1 = "Tracker 1: Response =" + str(req)
print(tracker_1)

res = req.json()

if req.ok is False:
    print('bullshit error #1')
    print("Bittex response: %s" % res['code'], file=sys.stderr)

1 Answers1

0

I can see two main problems:

  1. You are serialising/encoding the payload separately for the hash (with json.dumps and then bytes) and for the request (with the json=payload parameter to request.get). You don't have any way of knowing how the requests library will format your data, and if even one byte is different you will get a different hash. It is better to convert your data to bytes first, and then use the same bytes for the hash and for the request body.

  2. GET requests do not normally have a body (see this answer for more details), so it might be that the API is ignoring the payload you are sending. You should check the API docs to see if you really need to send a request body with GET requests.

Jack Taylor
  • 3,485
  • 13
  • 27
  • Double-checked the documentation, and it says 'if there is no payload, enter a blank string'. Which I will switch the code back to after my attempt at 'None'. I have tried it without the json=payload parameter and it seemed to make no difference. If i'm understanding this correctly, I should convert the blank string (or payload, when it has one) into bytes, then hash the bytes, and ignore the json=payload parameter in the get request, right? – Keeper151 May 09 '21 at 04:32
  • Yes, that's my understanding. Also, if you stop using the `json` argument you will need to add a `Content-Type: application/json` header. This is required by Bittrex, and is added by the requests library if you use the `json` argument, but will need to be manually added if you don't use the `json` argument. – Jack Taylor May 09 '21 at 15:09
  • Thank you for your responses, but it seems something is still not correct. Formatting sucks on these comments, so bear with me. I deleted the json=payload from my request header like so: '''req = requests.get(uri, headers=headers)''' and tried doing the blank string -> bytes -> hash sequence but the hashlib.sha512 won't accept the input in any form other than this: '''hashlib.sha512(bytes(str(content), "utf-8")).hexdigest()''' . Frankly I have no idea what I'm doing wrong (literally started python 9 weeks ago) and some sample snippets would be greatly appreciated. – Keeper151 May 10 '21 at 01:09
  • Sorry, don't have time now for code snippets, but here's another thought. `json.dumps("")` gives you the string `""`, but the API is expecting an actual empty string. Maybe the discrepancy between these two is what's causing you problems? – Jack Taylor May 10 '21 at 15:31