From 2127f1480ec226934eafebd00d1689df1a9d34cb Mon Sep 17 00:00:00 2001 From: Thales Zirbel Date: Mon, 2 Feb 2026 16:21:01 -0300 Subject: [PATCH 1/2] fix: ledger nano x on linus --- wallets/usbwallet/hub.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wallets/usbwallet/hub.go b/wallets/usbwallet/hub.go index c9c6f112..f464ca67 100644 --- a/wallets/usbwallet/hub.go +++ b/wallets/usbwallet/hub.go @@ -152,7 +152,11 @@ func (hub *Hub) refreshWallets() { for _, info := range infos { for _, id := range hub.productIDs { // Windows and macOS use UsageID matching, Linux uses Interface matching - if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { + // Ledger product IDs use MMII format where MM is device model and II is interface flags. + // Match either exact legacy IDs (0x0001, 0x0004, etc.) or device model prefix for + // WebUSB/app-specific IDs (e.g., 0x4011 matches 0x4000 prefix for Nano X with Ethereum app). + modelMatch := id >= 0x1000 && (info.ProductID>>8 == id>>8) + if (info.ProductID == id || modelMatch) && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { devices = append(devices, info) break } From d308247059bcb05dfa4d79909e5aeed3f8e05907 Mon Sep 17 00:00:00 2001 From: Thales Zirbel Date: Mon, 2 Feb 2026 16:21:23 -0300 Subject: [PATCH 2/2] fix encoding using default chain id --- ethereum/eip712/encoding.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/ethereum/eip712/encoding.go b/ethereum/eip712/encoding.go index 5292fa4e..cf47cb98 100644 --- a/ethereum/eip712/encoding.go +++ b/ethereum/eip712/encoding.go @@ -3,6 +3,7 @@ package eip712 import ( "errors" "fmt" + "strconv" apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes" @@ -101,8 +102,17 @@ func decodeAminoSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { return apitypes.TypedData{}, err } + // Extract the chain ID from the sign doc itself for EIP-712 domain + // This ensures we use the same chain ID that was used during signing + chainID := eip155ChainID + if aminoDoc.ChainID != "" { + if parsedChainID, err := parseChainID(aminoDoc.ChainID); err == nil { + chainID = parsedChainID + } + } + typedData, err := WrapTxToTypedData( - eip155ChainID, + chainID, signDocBytes, ) if err != nil { @@ -176,8 +186,17 @@ func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { body.Memo, ) + // Extract the chain ID from the sign doc itself for EIP-712 domain + // This ensures we use the same chain ID that was used during signing + chainID := eip155ChainID + if signDoc.ChainId != "" { + if parsedChainID, err := parseChainID(signDoc.ChainId); err == nil { + chainID = parsedChainID + } + } + typedData, err := WrapTxToTypedData( - eip155ChainID, + chainID, signBytes, ) if err != nil { @@ -227,3 +246,9 @@ func validatePayloadMessages(msgs []sdk.Msg) error { return nil } + +// parseChainID attempts to parse the chain ID string as a uint64. +// The chain ID in the sign doc should be the EIP-155 chain ID. +func parseChainID(chainIDStr string) (uint64, error) { + return strconv.ParseUint(chainIDStr, 10, 64) +}