hotstuff-python-sdk 0.0.1b3__tar.gz → 0.0.1b4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/PKG-INFO +1 -1
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/__init__.py +1 -1
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/apis/exchange.py +11 -7
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/utils/__init__.py +2 -1
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/utils/signing.py +17 -1
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/pyproject.toml +2 -5
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/LICENSE +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/README.md +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/apis/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/apis/info.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/apis/subscription.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/exceptions.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/account.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/collateral.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/op_codes.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/trading.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/vault.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/account.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/explorer.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/global.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/market.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/vault.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/subscription/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/subscription/channels.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/subscription/global.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/transports/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/transports/http.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/transports/websocket.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/types/__init__.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/types/clients.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/types/exchange.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/types/transports.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/utils/address.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/utils/endpoints.py +0 -0
- {hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/utils/nonce.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from typing import Optional, Any, Dict, Callable, Awaitable
|
|
3
3
|
from eth_account import Account
|
|
4
4
|
|
|
5
|
-
from hotstuff.utils import sign_action, NonceManager
|
|
5
|
+
from hotstuff.utils import sign_action, NonceManager, canonicalize_for_signing
|
|
6
6
|
from hotstuff.methods.exchange import (
|
|
7
7
|
trading as TM,
|
|
8
8
|
account as AM,
|
|
@@ -480,28 +480,32 @@ class ExchangeClient:
|
|
|
480
480
|
if "nonce" not in params or params["nonce"] is None:
|
|
481
481
|
params["nonce"] = await self.nonce()
|
|
482
482
|
|
|
483
|
-
#
|
|
483
|
+
# Canonicalize key order so msgpack bytes match backend (fixes "invalid order signer"
|
|
484
|
+
# for cancelByOid / cancelByCloid when backend expects deterministic key order)
|
|
485
|
+
params_canonical = canonicalize_for_signing(params)
|
|
486
|
+
|
|
487
|
+
# Sign the action (sign_action also canonicalizes; we pass canonical for consistency)
|
|
484
488
|
signature = sign_action(
|
|
485
489
|
wallet=self.wallet,
|
|
486
|
-
action=
|
|
490
|
+
action=params_canonical,
|
|
487
491
|
tx_type=EXCHANGE_OP_CODES[action],
|
|
488
492
|
is_testnet=self.transport.is_testnet,
|
|
489
493
|
)
|
|
490
494
|
|
|
491
495
|
if execute:
|
|
492
|
-
# Send to server
|
|
496
|
+
# Send to server with same canonical payload we signed
|
|
493
497
|
response = await self.transport.request(
|
|
494
498
|
"exchange",
|
|
495
499
|
{
|
|
496
500
|
"action": {
|
|
497
|
-
"data":
|
|
501
|
+
"data": params_canonical,
|
|
498
502
|
"type": str(EXCHANGE_OP_CODES[action]),
|
|
499
503
|
},
|
|
500
504
|
"signature": signature,
|
|
501
|
-
"nonce":
|
|
505
|
+
"nonce": params_canonical["nonce"],
|
|
502
506
|
},
|
|
503
507
|
signal,
|
|
504
508
|
)
|
|
505
509
|
return response
|
|
506
510
|
|
|
507
|
-
return {"params":
|
|
511
|
+
return {"params": params_canonical, "signature": signature}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Utilities package."""
|
|
2
2
|
from hotstuff.utils.endpoints import ENDPOINTS_URLS
|
|
3
3
|
from hotstuff.utils.nonce import NonceManager
|
|
4
|
-
from hotstuff.utils.signing import sign_action
|
|
4
|
+
from hotstuff.utils.signing import sign_action, canonicalize_for_signing
|
|
5
5
|
from hotstuff.utils.address import validate_ethereum_address
|
|
6
6
|
from hotstuff.methods.exchange.op_codes import EXCHANGE_OP_CODES
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@ __all__ = [
|
|
|
9
9
|
"ENDPOINTS_URLS",
|
|
10
10
|
"NonceManager",
|
|
11
11
|
"sign_action",
|
|
12
|
+
"canonicalize_for_signing",
|
|
12
13
|
"validate_ethereum_address",
|
|
13
14
|
"EXCHANGE_OP_CODES",
|
|
14
15
|
]
|
|
@@ -13,6 +13,20 @@ except ImportError:
|
|
|
13
13
|
_USE_NEW_API = False
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def canonicalize_for_signing(obj):
|
|
17
|
+
"""
|
|
18
|
+
Return a copy of obj with all dict keys sorted alphabetically, recursively.
|
|
19
|
+
Use this before signing and in the request body so msgpack bytes are
|
|
20
|
+
deterministic and match backend verification (fixes "invalid order signer"
|
|
21
|
+
for cancelByOid / cancelByCloid when key order differs from backend).
|
|
22
|
+
"""
|
|
23
|
+
if isinstance(obj, dict):
|
|
24
|
+
return {k: canonicalize_for_signing(v) for k, v in sorted(obj.items())}
|
|
25
|
+
if isinstance(obj, list):
|
|
26
|
+
return [canonicalize_for_signing(item) for item in obj]
|
|
27
|
+
return obj
|
|
28
|
+
|
|
29
|
+
|
|
16
30
|
def sign_action(
|
|
17
31
|
wallet: Account,
|
|
18
32
|
action: dict,
|
|
@@ -34,8 +48,10 @@ def sign_action(
|
|
|
34
48
|
Returns:
|
|
35
49
|
str: The signature (hex string)
|
|
36
50
|
"""
|
|
51
|
+
# Canonicalize key order so msgpack bytes match backend (deterministic signing)
|
|
52
|
+
canonical_action = canonicalize_for_signing(action)
|
|
37
53
|
# Encode action to msgpack
|
|
38
|
-
action_bytes = msgpack.packb(
|
|
54
|
+
action_bytes = msgpack.packb(canonical_action)
|
|
39
55
|
|
|
40
56
|
# Hash the payload
|
|
41
57
|
payload_hash = keccak(action_bytes)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "hotstuff-python-sdk"
|
|
3
|
-
version = "0.0.1-beta.
|
|
3
|
+
version = "0.0.1-beta.4"
|
|
4
4
|
description = "Python SDK for interacting with Hotstuff L1"
|
|
5
5
|
authors = ["hotstuff"]
|
|
6
6
|
license = "MIT"
|
|
@@ -20,9 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3.11",
|
|
21
21
|
"Programming Language :: Python :: 3.12",
|
|
22
22
|
]
|
|
23
|
-
packages = [
|
|
24
|
-
{ include = "hotstuff" }
|
|
25
|
-
]
|
|
23
|
+
packages = [{ include = "hotstuff" }]
|
|
26
24
|
|
|
27
25
|
[tool.poetry.dependencies]
|
|
28
26
|
python = "^3.8"
|
|
@@ -61,4 +59,3 @@ testpaths = ["tests"]
|
|
|
61
59
|
markers = [
|
|
62
60
|
"integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
|
|
63
61
|
]
|
|
64
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/__init__.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/account.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/collateral.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/op_codes.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/trading.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/exchange/vault.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/__init__.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/account.py
RENAMED
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/info/explorer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/methods/subscription/global.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hotstuff_python_sdk-0.0.1b3 → hotstuff_python_sdk-0.0.1b4}/hotstuff/transports/websocket.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|