Skip to content

Comments

devop: hw wallet typed message support#713

Merged
kvhnuke merged 1 commit intodevop/release-2-9from
devop/hw-typed-msg
Jun 18, 2025
Merged

devop: hw wallet typed message support#713
kvhnuke merged 1 commit intodevop/release-2-9from
devop/hw-typed-msg

Conversation

@kvhnuke
Copy link
Contributor

@kvhnuke kvhnuke commented Jun 13, 2025

Summary by CodeRabbit

  • New Features
    • Added support for signing EIP-712 typed messages with Ledger and Trezor hardware wallets for Ethereum accounts.
    • Introduced a new hardware wallet message display in the UI for typed message signing.
  • Enhancements
    • Streamlined typed message signing flow with improved abstraction for hardware and non-hardware wallets.
  • Compatibility
    • Added explicit handling and user feedback for unsupported typed message signing on non-Ethereum hardware wallets.
  • Dependencies
    • Added dependencies to support enhanced EIP-712 typed data signing functionality.
  • UI Updates
    • Updated transaction verification UI to prioritize displaying token recipient addresses when available.

@coderabbitai
Copy link

coderabbitai bot commented Jun 13, 2025

## Walkthrough

This change introduces EIP-712 typed message signing support for Ethereum hardware wallets, particularly Ledger and Trezor. It adds a unified `TypedMessageSigner` abstraction, updates UI components to display hardware wallet messages, and extends hardware wallet provider interfaces and implementations to handle typed message signing, with explicit support or rejection for each wallet and network.

## Changes

| File(s)                                                                                                                                                      | Change Summary                                                                                                 |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| packages/extension/src/providers/ethereum/ui/eth-sign-typedata.vue                                                                                        | Refactored signing logic to use new `TypedMessageSigner`; added hardware wallet message UI component; cleaned imports.          |
| packages/extension/src/providers/ethereum/ui/libs/signer.ts                                                                                               | Added exported `TypedMessageSigner` function for EIP-712 signing; updated exports.                             |
| packages/extension/src/providers/ethereum/ui/types.ts                                                                                                     | Added `SignerTypedMessageOptions` interface for typed message signing options.                                 |
| packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue                                                                                   | Changed displayed "To" address logic to prioritize token recipient address.                                   |
| packages/hw-wallets/package.json                                                                                                                          | Added `@metamask/eth-sig-util` and `@trezor/connect-plugin-ethereum` dependencies.                             |
| packages/hw-wallets/src/index.ts                                                                                                                          | Added `signTypedMessage` method to `HWwalletManager`.                                                          |
| packages/hw-wallets/src/types.ts                                                                                                                          | Added `SignTypedMessageRequest` interface and abstract method to `HWWalletProvider`.                           |
| packages/hw-wallets/src/ledger/ethereum/index.ts                                                                                                          | Implemented EIP-712 typed message signing in `LedgerEthereum`; added capability.                               |
| packages/hw-wallets/src/trezor/ethereum/index.ts                                                                                                          | Added `signTypedMessage` method using `transformTypedData` and TrezorConnect's `ethereumSignTypedData`; added capability.       |
| packages/hw-wallets/src/ledger/bitcoin/index.ts<br>packages/hw-wallets/src/ledger/solana/index.ts<br>packages/hw-wallets/src/ledger/substrate/index.ts<br>packages/hw-wallets/src/trezor/bitcoin/index.ts<br>packages/hw-wallets/src/trezor/solana/index.ts | Added stub `signTypedMessage` methods that reject with "not supported" errors for unsupported wallets/networks. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant UI as eth-sign-typedata.vue
    participant Signer as TypedMessageSigner
    participant HWManager as HWwalletManager
    participant Ledger as LedgerEthereum

    UI->>Signer: TypedMessageSigner(options)
    alt Hardware wallet
        Signer->>HWManager: signTypedMessage(request)
        HWManager->>Ledger: signTypedMessage(request)
        Ledger->>HWManager: signature / error
        HWManager->>Signer: signature / error
        Signer->>UI: signature / error
    else Software wallet
        Signer->>Internal: Compute hash and send for signing
        Internal->>Signer: signature / error
        Signer->>UI: signature / error
    end

Suggested reviewers

  • SemajaM

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between ef0b76b9e1f00c4d813abb5f4a19d9b8710f00dd and 73e81f6fe0a966bf19572f818e67e068334e6239.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `packages/swap/package.json` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* packages/swap/package.json

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: buildAll
* GitHub Check: test
* GitHub Check: test

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=enkryptcom/enKrypt&utm_content=713):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@github-actions
Copy link

github-actions bot commented Jun 13, 2025

💼 Build Files
chrome: enkrypt-chrome-eaf7e7e0.zip
firefox: enkrypt-firefox-eaf7e7e0.zip

💉 Virus total analysis
chrome: eaf7e7e0
firefox: eaf7e7e0

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (13)
packages/hw-wallets/src/types.ts (1)

111-112: Consider default implementation in abstract class

Every provider now copy-pastes a rejection stub. Moving the default to the base class keeps subclasses minimal and avoids string-divergence bugs (see Ledger Substrate below).

-abstract class HWWalletProvider {
+abstract class HWWalletProvider {
+  signTypedMessage(_req: SignTypedMessageRequest): Promise<string> {
+    return Promise.reject(new Error("signTypedMessage not supported"));
+  }

Subclasses that actually support the feature (e.g. LedgerEthereum) simply override.
Less code, fewer typos.

packages/hw-wallets/src/ledger/solana/index.ts (1)

85-89: Minor: prefer async + throw for uniform style

Elsewhere (signPersonalMessage, signTransaction) the error path uses throw inside async functions. For consistency and stack-trace clarity:

-  signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
-    return Promise.reject(
-      new Error("ledger-solana: signTypedMessage not supported"),
-    );
-  }
+  async signTypedMessage(): Promise<string> {
+    throw new Error("ledger-solana: signTypedMessage not supported");
+  }
packages/hw-wallets/src/ledger/substrate/index.ts (1)

94-98: Style consistency – see LedgerSolana comment

Same suggestion: convert to async + throw for uniformity across providers.

packages/hw-wallets/src/ledger/bitcoin/index.ts (1)

209-213: Use shared rejection logic to avoid duplication

This stub duplicates identical logic sprinkled across providers. If the base-class default recommended earlier is adopted, the whole method can be removed here.

-  signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
-    return Promise.reject(
-      new Error("ledger-bitcoin: signTypedMessage not supported"),
-    );
-  }
+  // remove – inherited default already rejects
packages/hw-wallets/src/trezor/ethereum/index.ts (1)

133-137: Make signTypedMessage async for interface symmetry

All other async capabilities in this provider (getAddress, signPersonalMessage, signTransaction) are declared with async.
Although returning Promise.reject(...) is technically fine, marking the method async and using a simple throw keeps the mental model consistent and avoids accidental refactors that treat it as a synchronous function.

-  signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
-    return Promise.reject(
-      new Error("trezor-ethereum: signTypedMessage not supported"),
-    );
-  }
+  async signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
+    throw new Error("trezor-ethereum: signTypedMessage not supported");
+  }
packages/hw-wallets/src/trezor/solana/index.ts (1)

71-75: Align style with other async members

Same reasoning as in the Ethereum provider: mark as async + throw for consistent style.

-  signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
-    return Promise.reject(
-      new Error("trezor-solana: signTypedMessage not supported"),
-    );
-  }
+  async signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
+    throw new Error("trezor-solana: signTypedMessage not supported");
+  }
packages/hw-wallets/src/trezor/bitcoin/index.ts (1)

119-123: Minor consistency tweak

For parity with the rest of the class & other providers, prefer async + throw:

-  signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
-    return Promise.reject(
-      new Error("trezor-bitcoin: signTypedMessage not supported"),
-    );
-  }
+  async signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
+    throw new Error("trezor-bitcoin: signTypedMessage not supported");
+  }
packages/hw-wallets/src/index.ts (1)

71-76: Optional DRY refactor opportunity

getAddress, signPersonalMessage, signTypedMessage, and signTransaction share a “resolve-provider + delegate” pattern.
A tiny private helper would remove repetition:

#delegate<T extends keyof HWWalletProvider>(
  method: T,
  options: Parameters<HWWalletProvider[T]>[0]
): ReturnType<HWWalletProvider[T]> { ... }

Not blocking, but worth considering to keep this dispatcher lean.

packages/extension/src/providers/ethereum/ui/eth-sign-typedata.vue (2)

105-117: Prevent double-sign clicks & lost rejections

approve() fires TypedMessageSigner() but does not disable the “Sign” button or await the promise.
If a user double-clicks, the function is executed twice and two concurrent background requests are produced, which may confuse both Ledger and the dApp.

Add a pending flag that disables the right button until the promise settles, and await the signer to surface any synchronous throw.


54-55: Component registration mismatch risk

With <script setup> an imported component is automatically exposed under its import name (HardwareWalletMsg).
In templates Vue resolves both HardwareWalletMsg and hardware-wallet-msg, but the kebab-case variant relies on the kebabisation heuristic.
Sticking to <HardwareWalletMsg/> avoids template-compiler edge-cases and improves grep-ability.

packages/extension/src/providers/ethereum/ui/libs/signer.ts (2)

124-131: Surface V1-not-supported earlier

The hardware-wallet branch rejects V1 only after the call is made.
Fail fast by validating version before instantiating HWwallet – saves an unnecessary USB round-trip.


156-169: Shadowed version constant

Inside the software-wallet branch you redeclare const version = … which shadows the parameter captured above.
The code works, but the extra binding is unnecessary noise.

-const version = options.version as SignTypedDataVersion;
-const typedData = options.typedData;
+const version = options.version as SignTypedDataVersion;
+const { typedData } = options;
packages/hw-wallets/src/ledger/ethereum/index.ts (1)

184-191: Advertise capability only when firmware is new enough

typedMessage support requires Ledger-Ethereum ≥ 1.10.0.
Blindly announcing the capability may mislead the UI on older firmware, causing silent failures.

Consider detecting the app version in init() and conditionally returning the capability.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13df0aa and 26cf4a7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • packages/extension/src/providers/ethereum/ui/eth-sign-typedata.vue (3 hunks)
  • packages/extension/src/providers/ethereum/ui/libs/signer.ts (2 hunks)
  • packages/extension/src/providers/ethereum/ui/types.ts (1 hunks)
  • packages/hw-wallets/package.json (1 hunks)
  • packages/hw-wallets/src/index.ts (2 hunks)
  • packages/hw-wallets/src/ledger/bitcoin/index.ts (2 hunks)
  • packages/hw-wallets/src/ledger/ethereum/index.ts (3 hunks)
  • packages/hw-wallets/src/ledger/solana/index.ts (2 hunks)
  • packages/hw-wallets/src/ledger/substrate/index.ts (2 hunks)
  • packages/hw-wallets/src/trezor/bitcoin/index.ts (2 hunks)
  • packages/hw-wallets/src/trezor/ethereum/index.ts (2 hunks)
  • packages/hw-wallets/src/trezor/solana/index.ts (2 hunks)
  • packages/hw-wallets/src/types.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
packages/hw-wallets/src/ledger/substrate/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/trezor/ethereum/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/ledger/bitcoin/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/trezor/solana/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/ledger/solana/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/trezor/bitcoin/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
packages/hw-wallets/src/index.ts (1)
packages/hw-wallets/src/types.ts (1)
  • SignTypedMessageRequest (56-62)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: buildAll
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (1)
packages/hw-wallets/package.json (1)

60-62:

Details

❓ Verification inconclusive

Pin indirect dependency to avoid accidental breaking changes

@metamask/eth-sig-util follows sem-ver but occasionally ships breaking changes in minor bumps. Declaring the range as ^8.2.0 will auto-upgrade to any 8.x release and may break the Ledger EIP-712 logic without notice.
Consider hard-pinning or using ~8.2.0 until a compatibility matrix is in place.

-    "@metamask/eth-sig-util": "^8.2.0",
+    "@metamask/eth-sig-util": "~8.2.0",

Action Required: Constrain @metamask/eth-sig-util to patch updates

Minor version bumps of @metamask/eth-sig-util have historically shipped breaking changes that can disrupt Ledger’s EIP-712 handling. Until we have a compatibility matrix, it’s safer to pin to the 8.2.x patch range.

• File: packages/hw-wallets/package.json
• Lines: 60–62

Suggested diff:

-    "@metamask/eth-sig-util": "^8.2.0",
+    "@metamask/eth-sig-util": "~8.2.0",

Comment on lines 56 to 62
export interface SignTypedMessageRequest extends BaseRequest {
domain: Record<string, unknown>;
message: Record<string, unknown>;
types: Record<string, any>;
primaryType: string;
version: "V3" | "V4";
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Tighten types typing to the canonical EIP-712 shape

types: Record<string, any> loses every bit of compile-time safety and allows malformed payloads to slip through.
You already depend on @metamask/eth-sig-util, which exports TypedData helpers:

import type { MessageTypes, TypedMessage } from "@metamask/eth-sig-util";
-  types: Record<string, any>;
+  types: MessageTypes;

This gives editors/full CI feedback and guarantees that every wallet receives a valid structure.

🤖 Prompt for AI Agents
In packages/hw-wallets/src/types.ts around lines 56 to 62, the `types` property
in the SignTypedMessageRequest interface is currently typed as `Record<string,
any>`, which lacks compile-time safety. To fix this, import the appropriate
types such as `MessageTypes` from `@metamask/eth-sig-util` and replace the
`types` property's type with `MessageTypes` to enforce the canonical EIP-712
structure and improve type safety.

Comment on lines 94 to 98
signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
return Promise.reject(
new Error("ledger-bitcoin: signTypedMessage not supported"),
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect error prefix – copy/paste artifact

The rejection message says ledger-bitcoin instead of ledger-substrate, which will mislead support and telemetry.

-      new Error("ledger-bitcoin: signTypedMessage not supported"),
+      new Error("ledger-substrate: signTypedMessage not supported"),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
return Promise.reject(
new Error("ledger-bitcoin: signTypedMessage not supported"),
);
}
signTypedMessage(_request: SignTypedMessageRequest): Promise<string> {
return Promise.reject(
new Error("ledger-substrate: signTypedMessage not supported"),
);
}
🤖 Prompt for AI Agents
In packages/hw-wallets/src/ledger/substrate/index.ts around lines 94 to 98, the
error message in the rejected promise incorrectly uses the prefix
"ledger-bitcoin" instead of "ledger-substrate". Update the error message string
to use "ledger-substrate" to accurately reflect the source and avoid confusion
in support and telemetry.

Comment on lines 40 to 45
export interface SignerTypedMessageOptions {
typedData: any;
version: 'V3' | 'V4';
network: BaseNetwork;
account: EnkryptAccount;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Tighten typedData typing to improve type-safety

any forfeits the main benefit of introducing a dedicated interface.
@metamask/eth-sig-util exports TypedMessage / TypedData helpers you can leverage:

-import interface SignerTypedMessageOptions {
-  typedData: any;
+import { TypedMessage } from '@metamask/eth-sig-util';
+
+export interface SignerTypedMessageOptions {
+  /** EIP-712 typed data payload */
+  typedData: TypedMessage<any>;

This provides compile-time guarantees and IntelliSense when constructing the payload.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/extension/src/providers/ethereum/ui/types.ts around lines 40 to 45,
the typedData property is currently typed as any, which reduces type safety.
Replace the any type with the appropriate TypedMessage or TypedData type
imported from @metamask/eth-sig-util to provide compile-time type checking and
better IntelliSense support. Ensure you import the type correctly and update the
interface definition accordingly.

Comment on lines 141 to 165
signTypedMessage(request: SignTypedMessageRequest): Promise<string> {
const messageHash = TypedDataUtils.hashStruct(
request.primaryType,
request.message,
request.types,
request.version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4,
);
const domainHash = TypedDataUtils.hashStruct(
"EIP712Domain",
request.domain,
request.types,
request.version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4,
);
const connection = new EthApp(this.transport);
return connection
.signEIP712HashedMessage(
request.pathType.path.replace(`{index}`, request.pathIndex),
bufferToHex(domainHash, true),
bufferToHex(messageHash, true),
)
.then((result) => {
const v = BigInt(result.v - 27);
return toRpcSig(v, hexToBuffer(result.r), hexToBuffer(result.s));
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Guard unexpected Ledger v values

signEIP712HashedMessage normally returns v ∈ {27,28}.
If the app ever changes and returns a raw 0/1, v - 27 underflows to a huge unsigned bigint, producing an invalid RPC-sig.

-const v = BigInt(result.v - 27);
+const rawV = BigInt(result.v);
+if (rawV !== 27n && rawV !== 28n) {
+  throw new Error(`ledger-ethereum: unexpected v=${result.v}`);
+}
+const v = rawV - 27n;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
signTypedMessage(request: SignTypedMessageRequest): Promise<string> {
const messageHash = TypedDataUtils.hashStruct(
request.primaryType,
request.message,
request.types,
request.version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4,
);
const domainHash = TypedDataUtils.hashStruct(
"EIP712Domain",
request.domain,
request.types,
request.version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4,
);
const connection = new EthApp(this.transport);
return connection
.signEIP712HashedMessage(
request.pathType.path.replace(`{index}`, request.pathIndex),
bufferToHex(domainHash, true),
bufferToHex(messageHash, true),
)
.then((result) => {
const v = BigInt(result.v - 27);
return toRpcSig(v, hexToBuffer(result.r), hexToBuffer(result.s));
});
}
.then((result) => {
- const v = BigInt(result.v - 27);
+ const rawV = BigInt(result.v);
+ if (rawV !== 27n && rawV !== 28n) {
+ throw new Error(`ledger-ethereum: unexpected v=${result.v}`);
+ }
+ const v = rawV - 27n;
return toRpcSig(v, hexToBuffer(result.r), hexToBuffer(result.s));
});
🤖 Prompt for AI Agents
In packages/hw-wallets/src/ledger/ethereum/index.ts around lines 141 to 165, the
code assumes the Ledger's returned 'v' value is always 27 or 28, but if it
returns 0 or 1, subtracting 27 causes an underflow and invalid signature. To fix
this, add a guard to check if 'v' is 0 or 1 and if so, add 27 before converting
to BigInt; otherwise, proceed as usual. This ensures the 'v' value is correctly
normalized before creating the RPC signature.

@kvhnuke kvhnuke changed the base branch from develop to devop/release-2-9 June 18, 2025 18:02
@kvhnuke kvhnuke merged commit 8c4474d into devop/release-2-9 Jun 18, 2025
5 checks passed
@kvhnuke kvhnuke deleted the devop/hw-typed-msg branch June 18, 2025 18:02
@coderabbitai coderabbitai bot mentioned this pull request Jun 18, 2025
@coderabbitai coderabbitai bot mentioned this pull request Jun 30, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 16, 2025
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.

2 participants