Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion hyperliquid/utils/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ def add_multi_sig_types(sign_types):
}
)
if not enriched:
print('"hyperliquidChain" missing from sign_types. sign_types was not enriched with multi-sig signing types')
raise ValueError(
'"hyperliquidChain" missing from sign_types, so sign_types cannot be enriched with the multi-sig '
"signing types. Without payloadMultiSigUser and outerSigner the signature is not bound to the "
"multi-sig user or the outer signer and will not be accepted."
)
return enriched_sign_types


Expand Down
40 changes: 40 additions & 0 deletions tests/signing_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

from hyperliquid.exchange import _multi_sig_payload_action
from hyperliquid.utils.signing import (
USD_SEND_SIGN_TYPES,
OrderRequest,
ScheduleCancelAction,
action_hash,
add_multi_sig_types,
construct_phantom_agent,
float_to_int_for_hashing,
order_request_to_order_wire,
order_wires_to_order_action,
sign_l1_action,
sign_multi_sig_user_signed_action_payload,
sign_usd_transfer_action,
sign_withdraw_from_bridge_action,
)
Expand Down Expand Up @@ -228,6 +231,43 @@ def test_multi_sig_user_set_abstraction_payload_uses_wire_enum():
assert action["abstraction"] == "disabled"


def test_add_multi_sig_types_rejects_types_without_hyperliquid_chain():
# eth_account ignores message keys that have no matching entry in the EIP-712 types, so if the
# multi-sig fields are silently left out the resulting signature is byte-identical to a plain
# single-signer one and carries no binding to the multi-sig user or the outer signer.
wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123")
types_without_chain = [t for t in USD_SEND_SIGN_TYPES if t["name"] != "hyperliquidChain"]
action = {
"destination": "0x5e9ee1089755c3435139848e47e6635505d5a13a",
"amount": "1",
"time": 1687816341423,
}

with pytest.raises(ValueError):
add_multi_sig_types(types_without_chain)

with pytest.raises(ValueError):
sign_multi_sig_user_signed_action_payload(
wallet,
action,
False,
types_without_chain,
"HyperliquidTransaction:UsdSend",
"0x0000000000000000000000000000000000000005",
wallet.address,
)

enriched = add_multi_sig_types(USD_SEND_SIGN_TYPES)
assert [t["name"] for t in enriched] == [
"hyperliquidChain",
"payloadMultiSigUser",
"outerSigner",
"destination",
"amount",
"time",
]


def test_create_sub_account_action():
wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123")
action = {
Expand Down