Skip to content

Commit c3e0291

Browse files
committed
Raise instead of warn when multi-sig sign types cannot be enriched
add_multi_sig_types inserts payloadMultiSigUser and outerSigner after the hyperliquidChain entry. When sign_types has no hyperliquidChain entry it printed a warning and returned the list unchanged, then signing carried on with the un-enriched types. eth_account builds the EIP-712 hash from the type list and ignores message keys with no matching type entry, so add_multi_sig_fields still puts payloadMultiSigUser and outerSigner into the message and they are silently dropped from the hash. The result is a signature identical to a plain single-signer one for the same action: BAD = [t for t in USD_SEND_SIGN_TYPES if t["name"] != "hyperliquidChain"] sign_multi_sig_user_signed_action_payload(w, a, False, BAD, ..., msu, outer) == sign_user_signed_action(w, a, BAD, ..., False) # True It carries no binding to the multi-sig user or the outer signer, so it is not usable as an inner multi-sig signature. All of the sign types exported from this module have hyperliquidChain first, so this only affects callers passing their own type list, which is the case for any action the SDK does not have a helper for yet. A stdout warning is easy to miss there. Raising ValueError instead. No signature that the chain accepts today changes, since the un-enriched path could not produce one.
1 parent 2fdb18f commit c3e0291

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

hyperliquid/utils/signing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ def add_multi_sig_types(sign_types):
273273
}
274274
)
275275
if not enriched:
276-
print('"hyperliquidChain" missing from sign_types. sign_types was not enriched with multi-sig signing types')
276+
raise ValueError(
277+
'"hyperliquidChain" missing from sign_types, so sign_types cannot be enriched with the multi-sig '
278+
"signing types. Without payloadMultiSigUser and outerSigner the signature is not bound to the "
279+
"multi-sig user or the outer signer and will not be accepted."
280+
)
277281
return enriched_sign_types
278282

279283

tests/signing_test.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
from hyperliquid.exchange import _multi_sig_payload_action
66
from hyperliquid.utils.signing import (
7+
USD_SEND_SIGN_TYPES,
78
OrderRequest,
89
ScheduleCancelAction,
910
action_hash,
11+
add_multi_sig_types,
1012
construct_phantom_agent,
1113
float_to_int_for_hashing,
1214
order_request_to_order_wire,
1315
order_wires_to_order_action,
1416
sign_l1_action,
17+
sign_multi_sig_user_signed_action_payload,
1518
sign_usd_transfer_action,
1619
sign_withdraw_from_bridge_action,
1720
)
@@ -228,6 +231,43 @@ def test_multi_sig_user_set_abstraction_payload_uses_wire_enum():
228231
assert action["abstraction"] == "disabled"
229232

230233

234+
def test_add_multi_sig_types_rejects_types_without_hyperliquid_chain():
235+
# eth_account ignores message keys that have no matching entry in the EIP-712 types, so if the
236+
# multi-sig fields are silently left out the resulting signature is byte-identical to a plain
237+
# single-signer one and carries no binding to the multi-sig user or the outer signer.
238+
wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123")
239+
types_without_chain = [t for t in USD_SEND_SIGN_TYPES if t["name"] != "hyperliquidChain"]
240+
action = {
241+
"destination": "0x5e9ee1089755c3435139848e47e6635505d5a13a",
242+
"amount": "1",
243+
"time": 1687816341423,
244+
}
245+
246+
with pytest.raises(ValueError):
247+
add_multi_sig_types(types_without_chain)
248+
249+
with pytest.raises(ValueError):
250+
sign_multi_sig_user_signed_action_payload(
251+
wallet,
252+
action,
253+
False,
254+
types_without_chain,
255+
"HyperliquidTransaction:UsdSend",
256+
"0x0000000000000000000000000000000000000005",
257+
wallet.address,
258+
)
259+
260+
enriched = add_multi_sig_types(USD_SEND_SIGN_TYPES)
261+
assert [t["name"] for t in enriched] == [
262+
"hyperliquidChain",
263+
"payloadMultiSigUser",
264+
"outerSigner",
265+
"destination",
266+
"amount",
267+
"time",
268+
]
269+
270+
231271
def test_create_sub_account_action():
232272
wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123")
233273
action = {

0 commit comments

Comments
 (0)