The problem of invalid signature when I am posting data

72 Views Asked by At

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&timestamp=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)
1

There are 1 best solutions below

0
sndmndss On

The thing in this whole history is that this API is very new(and bad). So when it accepts body with this params:

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,
        }

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.