Преглед изворни кода

fix: align signed body with post payload

lxy пре 1 месец
родитељ
комит
e85befe200
2 измењених фајлова са 45 додато и 3 уклоњено
  1. 3 1
      okx_codex_trader/okx_client.py
  2. 42 2
      tests/test_okx_client.py

+ 3 - 1
okx_codex_trader/okx_client.py

@@ -83,13 +83,15 @@ class OkxClient:
             "OK-ACCESS-PASSPHRASE": self.config.api_passphrase,
             "x-simulated-trading": "1",
         }
+        if json_body is not None:
+            headers["Content-Type"] = "application/json"
         try:
             response = self.session.request(
                 method.upper(),
                 f"{self.base_url}{path}",
                 headers=headers,
                 params=params,
-                json=json_body,
+                data=body if json_body is not None else None,
             )
         except Exception:
             raise self._transport_error() from None

+ 42 - 2
tests/test_okx_client.py

@@ -1,6 +1,7 @@
 import base64
 import hashlib
 import hmac
+import json as json_module
 from dataclasses import dataclass
 from urllib.parse import urlencode, urlparse
 
@@ -30,6 +31,7 @@ class RecordedRequest:
     headers: dict[str, str]
     params: dict[str, object] | None
     json_body: dict[str, object] | None
+    body: str | None
 
 
 class DummySession:
@@ -43,6 +45,10 @@ class DummySession:
     def last_json_body(self) -> dict[str, object] | None:
         return self.last_request.json_body if self.last_request else None
 
+    @property
+    def last_body(self) -> str | None:
+        return self.last_request.body if self.last_request else None
+
     def request(
         self,
         method: str,
@@ -51,16 +57,21 @@ class DummySession:
         headers: dict[str, str] | None = None,
         params: dict[str, object] | None = None,
         json: dict[str, object] | None = None,
+        data: str | None = None,
     ) -> DummyResponse:
+        parsed_json = json
+        if parsed_json is None and data is not None:
+            parsed_json = json_module.loads(data)
         self.last_request = RecordedRequest(
             method=method,
             url=url,
             headers=headers or {},
             params=params,
-            json_body=json,
+            json_body=parsed_json,
+            body=data,
         )
         self.request_paths.append(urlparse(url).path)
-        self.request_bodies.append(json)
+        self.request_bodies.append(parsed_json)
         if self._responses:
             response = self._responses.pop(0)
             if isinstance(response, Exception):
@@ -299,6 +310,35 @@ def test_signed_demo_request_attaches_headers():
     assert request.headers["OK-ACCESS-SIGN"] == expected_signature
 
 
+def test_signed_post_request_uses_actual_serialized_body_bytes():
+    session = DummySession(
+        [
+            instrument_response(),
+            account_config_response(pos_mode="long_short_mode"),
+            leverage_response(),
+            place_order_response(),
+        ]
+    )
+    client = OkxClient(config=sample_config(), session=session)
+
+    client.place_demo_order(symbol="ETH-USDT-SWAP", signal=limit_short_signal(), margin_usdt=100)
+
+    request = session.last_request
+    assert request is not None
+    assert request.method == "POST"
+    assert request.body is not None
+    timestamp = request.headers["OK-ACCESS-TIMESTAMP"]
+    path = urlparse(request.url).path
+    expected_signature = base64.b64encode(
+        hmac.new(
+            b"secret",
+            f"{timestamp}{request.method}{path}{request.body}".encode(),
+            hashlib.sha256,
+        ).digest()
+    ).decode()
+    assert request.headers["OK-ACCESS-SIGN"] == expected_signature
+
+
 def test_get_candles_returns_chronological_ascending_order():
     session = DummySession([descending_candles_response()])
     client = OkxClient(config=sample_config(), session=session)