The problem is in trying to send post request with aiohttp on some exchange API. With this request I must send this headers:
headers = {
'X-Timestamp': str(timestamp),
'X-Window': str(self.WINDOW),
'X-API-Key': self.public_key,
'X-Signature': signature
}
all headers are correct(I tested them), except signature.
I always have "Invalid signature" if it has signed format.
the structure of it must be like that:
instruction=orderExecute&postOnly=False&price=1&quantity=10&selfTradePrevention=Allow&side=Bid&symbol=SOL_USDC&timeInForce=IOC×tamp=1710451343478&window=6000
This is what I tried to POST
AND it must be signed by the private_key, that is a pair for public key for headers, only then I send data with some body params.
!!!"Invalid signature"!!!.
body "params" are correct(changing them gives another responce)
"headers" are also correct, same reason as for body "params"
API docs with signature structure: https://docs.backpack.exchange/#section/Authentication
That is my code
class Site:
WINDOW = 6000
def __init__(self, token, private_key):
self.public_key = token
self.private_key = private_key
async def headers(self, params: dict, instruction: str) -> dict:
timestamp = await self._unix_time()
params["window"] = self.WINDOW
params["timestamp"] = timestamp
sorted_params = sorted(params.items())
query_string = f"instruction={instruction}&"+'&'.join(f"{key}={value}" for key, value in sorted_params)
signature = await self._sign(query_string)
headers = {
'X-Timestamp': str(timestamp),
'X-Window': str(self.WINDOW),
'X-API-Key': self.public_key,
'X-Signature': signature
}
return headers
async def _sign(self, data):
private_key_bytes = base64.b64decode(self.private_key)
private_key = Ed25519PrivateKey.from_private_bytes(private_key_bytes)
signature = private_key.sign(data.encode())
signature_base64 = base64.b64encode(signature).decode()
return signature_base64
@staticmethod
async def _unix_time():
async with aiohttp.ClientSession() as session:
async with session.get("https://api.backpack.exchange/api/v1/time") as response:
return await response.text()
class Trade(Site):
def __init__(self, public_key, private_key):
super().__init__(public_key, private_key)
async def buy_order(self):
params = {
"orderType": OrderType.LIMIT.value,
"postOnly": PostOnly.FALSE.value,
"price": "1",
"quantity": "10",
"selfTradePrevention": SelfTradePrevention.ALLOW.value,
"side": Side.BUY.value,
"symbol": Symbol.SOL.value,
"timeInForce": TimeInForce.IOC.value,
}
headers = await self.headers(params=params, instruction=Instruction.ORDER_EXECUTE.value)
headers['Content-Type'] = 'application/json; charset=utf-8'
body = json.dumps(params)
r = await _handle_post(headers=headers, body=body)
The thing in this whole history is that this API is very new(and bad). So when it accepts body with this params:
and if you will try delete some of this data, you will get response that you have something wrong in body. When not it says that the problem is in signature(it's not).
param "postOnly"(True or False, no matter) conflicts with something, and that was the signature problem.