|
1 | | -"""Bitget Wallet ToB API client with built-in signing.""" |
| 1 | +"""Bitget Wallet API client with BKHmacAuth signing.""" |
| 2 | +from __future__ import annotations |
2 | 3 |
|
3 | | -import base64 |
4 | 4 | import hashlib |
5 | | -import hmac |
6 | 5 | import json |
7 | 6 | import os |
8 | 7 | import time |
9 | 8 |
|
10 | 9 | import requests |
11 | 10 |
|
12 | | -BASE_URL = "https://bopenapi.bgwapi.io" |
| 11 | +BASE_URL = "https://copenapi.bgwapi.io" |
| 12 | +WALLET_ID = os.environ.get("BGW_WALLET_ID", "") |
13 | 13 |
|
14 | | -# Public demo credentials for testing. These may change over time — |
15 | | -# if they stop working, please update to get the latest keys. |
16 | | -# Public demo credentials for testing purposes. These may change over time — |
17 | | -# if they stop working, please update to get the latest keys. |
18 | | -# Override via BGW_API_KEY / BGW_API_SECRET env vars. |
19 | | -API_KEY = os.environ.get("BGW_API_KEY", "4843D8C3F1E20772C0E634EDACC5C5F9A0E2DC92") |
20 | | -API_SECRET = os.environ.get("BGW_API_SECRET", "F2ABFDC684BDC6775FD6286B8D06A3AAD30FD587") |
21 | | -PARTNER_CODE = os.environ.get("BGW_PARTNER_CODE", "bgw_swap_public") |
22 | 14 |
|
23 | | - |
24 | | -def _sign(api_path: str, body_str: str, timestamp: str) -> str: |
25 | | - content = { |
26 | | - "apiPath": api_path, |
27 | | - "body": body_str, |
28 | | - "x-api-key": API_KEY, |
29 | | - "x-api-timestamp": timestamp, |
30 | | - } |
31 | | - payload = json.dumps(dict(sorted(content.items())), separators=(",", ":")) |
32 | | - sig = hmac.new(API_SECRET.encode(), payload.encode(), hashlib.sha256).digest() |
33 | | - return base64.b64encode(sig).decode() |
| 15 | +def _make_sign(method: str, path: str, body_str: str, ts: str) -> str: |
| 16 | + """BKHmacAuth signature: SHA256(Method + Path + Body + Timestamp).""" |
| 17 | + message = method + path + body_str + ts |
| 18 | + digest = hashlib.sha256(message.encode("utf-8")).hexdigest() |
| 19 | + return "0x" + digest |
34 | 20 |
|
35 | 21 |
|
36 | 22 | def request(path: str, body: dict | None = None) -> dict: |
37 | | - timestamp = str(int(time.time() * 1000)) |
38 | | - body_str = json.dumps(body, separators=(",", ":"), sort_keys=True) if body else "" |
39 | | - signature = _sign(path, body_str, timestamp) |
40 | | - |
| 23 | + """POST request with BKHmacAuth signing.""" |
| 24 | + ts = str(int(time.time() * 1000)) |
| 25 | + body_str = json.dumps(body, separators=(",", ":"), ensure_ascii=False) if body else "" |
| 26 | + sign = _make_sign("POST", path, body_str, ts) |
| 27 | + token_val = WALLET_ID if WALLET_ID else "toc_agent" |
41 | 28 | headers = { |
42 | 29 | "Content-Type": "application/json", |
43 | | - "x-api-key": API_KEY, |
44 | | - "x-api-timestamp": timestamp, |
45 | | - "x-api-signature": signature, |
| 30 | + "channel": "toc_agent", |
| 31 | + "brand": "toc_agent", |
| 32 | + "clientversion": "10.0.0", |
| 33 | + "language": "en", |
| 34 | + "token": token_val, |
| 35 | + "X-SIGN": sign, |
| 36 | + "X-TIMESTAMP": ts, |
46 | 37 | } |
47 | | - if "/swapx/" in path: |
48 | | - headers["Partner-Code"] = PARTNER_CODE |
49 | | - |
50 | 38 | resp = requests.post(BASE_URL + path, data=body_str or None, headers=headers, timeout=30) |
51 | 39 | if resp.status_code != 200: |
52 | | - return {"error": f"HTTP {resp.status_code}", "message": resp.text[:500]} |
| 40 | + return {"status": -1, "error_code": resp.status_code, "msg": resp.text[:500]} |
53 | 41 | return resp.json() |
0 commit comments