Skip to content

fix(eip712): don't truncate colon-namespaced type names in struct hashing#51

Merged
BitHighlander merged 1 commit into
masterfrom
fix/hyperliquid-eip712-colon-typename
Jul 5, 2026
Merged

fix(eip712): don't truncate colon-namespaced type names in struct hashing#51
BitHighlander merged 1 commit into
masterfrom
fix/hyperliquid-eip712-colon-typename

Conversation

@BitHighlander

Copy link
Copy Markdown
Collaborator

Bug

Hyperliquid's dApp signs EIP-712 typed data with primaryType values like
"HyperliquidTransaction:ApproveAgent" — a colon-namespaced type name. This
is one of ~12 sibling action types Hyperliquid uses for user-signed actions
(UsdSend, Withdraw, SpotSend, TokenDelegate, ApproveBuilderFee, etc.),
all sharing this same naming convention (confirmed against the reference
hyperliquid-python-sdk signing.py).

ethereum.ts's ethSignTypedData calls into the eip-712 npm package's
getStructHash, whose dependency walker matched type names against
TYPE_REGEX = /^\w+/ — intended to strip a trailing array suffix
(Person[]Person) but actually truncating any type name at its
first non-word character. "HyperliquidTransaction:ApproveAgent" truncated
to "HyperliquidTransaction", which isn't a key in typedData.types, so
getDependencies returned an empty list, encodeType destructured
primary = undefined, and typedData.types[undefined].map(...) threw a
TypeError — caught by a generic catch-all and surfaced to users as
"Failed to sign typed ETH message".

Fix

Patched via patch-package (patches/eip-712+1.0.0.patch, applied to both
lib/cjs and lib/es builds): only strip a trailing array suffix via the
existing ARRAY_REGEX, otherwise use the type name verbatim. This is a
generic fix — it covers every HyperliquidTransaction:* action, not just
ApproveAgent.

Tests

  • packages/hdwallet-keepkey/src/eip712-struct-hash.test.ts: added known-answer
    vectors for HyperliquidTransaction:ApproveAgent and
    HyperliquidTransaction:UsdSend (computed against the patched library, to
    pin correctness of the actual hash output — not just "doesn't throw").
  • Added a direct getDependencies unit check for the colon-namespaced
    primaryType.
  • Verified the new tests fail without the patch (2 failures) and pass with it
    (11/11 in the full struct-hash suite; 112/112 across the whole
    hdwallet-keepkey package).

…hing

The eip-712 package's dependency walker matched type names against
/^\w+/, intended to strip a trailing array suffix (Person[] -> Person)
but actually truncating ANY type name at its first non-word character.
Hyperliquid's dApp uses primaryType values like
"HyperliquidTransaction:ApproveAgent" (and ~11 sibling actions -
UsdSend, Withdraw, SpotSend, TokenDelegate, etc.) which all share this
colon-namespaced convention. The truncated lookup found nothing in
typedData.types, returned an empty dependency list, and encodeType
crashed on typedData.types[undefined] - surfaced to users as a generic
"Failed to sign typed ETH message".

Patched via patch-package (patches/eip-712+1.0.0.patch): only strip a
trailing array suffix via ARRAY_REGEX, otherwise use the type name
verbatim. Added known-answer regression vectors for two Hyperliquid
action types (ApproveAgent, UsdSend) plus a direct getDependencies unit
check, so a future `yarn install` that drops the patch fails loudly.
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hdwallet-sandbox Ready Ready Preview, Comment Jul 5, 2026 2:35pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant