Skip to content

Commit 3d488b1

Browse files
feat: add 7702 methods to ledger (#564)
<!-- Thanks for your contribution! Take a moment to answer these questions so that reviewers have the information they need to properly understand your changes: * What is the current state of things and why does it need to change? * What is the solution your changes offer and how does it work? Are there any issues or other links reviewers should consult to understand this pull request better? For instance: * Fixes #12345 * See: #67890 --> This PR adds the 7702 methods to the ledger keyring. The method itself is not usable until the dmk support has been added. ## Examples <!-- Are there any examples of this change being used in another repository? When considering changes to the MetaMask module template, it's strongly preferred that the change be experimented with in another repository first. This gives reviewers a better sense of how the change works, making it less likely the change will need to be reverted or adjusted later. --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes hardware signing and signature recovery for personal_sign/typed data; EIP-7702 is new delegation signing surface, though iframe/mobile paths are not live yet. > > **Overview** > Adds **EIP-7702 delegation authorization signing** to the Ledger Ethereum keyring and wires it through the V2 account API. > > `LedgerKeyring.signEip7702Authorization` unlocks the account, calls the bridge’s new `deviceSignDelegationAuthorization` (chain id, contract address without `0x`, nonce), builds a signature with **yParity** (`00`/`01`) instead of legacy `27`/`28`, and verifies with `recoverEIP7702Authorization`. The `LedgerBridge` interface gains delegation types and `deviceSignDelegationAuthorization`; **iframe and mobile bridges throw** until DMK/device support exists. > > **personal_sign** and **typed data** now parse Ledger’s `v` via `#parseLedgerRecoveryParam` (decimal, bare hex like `'1b'`, `0x`/`0X` hex, numbers) instead of `parseInt(..., 10)`, fixing wrong recovery when the device returns hex `v`. > > V2 `LedgerKeyring` advertises `EthKeyringMethod.SignEip7702Authorization` on EOA accounts. Changelog and Jest coverage thresholds are updated; extensive unit tests cover 7702 signing and `v` parsing edge cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c91b13d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Gustavo Antunes <17601467+gantunesr@users.noreply.github.com>
1 parent a5e7517 commit 3d488b1

9 files changed

Lines changed: 529 additions & 7 deletions

File tree

packages/keyring-eth-ledger-bridge/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add EIP-7702 authorization signing to the Ledger keyring ([#564](https://github.com/MetaMask/accounts/pull/564))
13+
- Not yet functional: both iframe and mobile bridges throw until DMK support lands.
14+
- Fixes hex `v` parsing (`'1b'`) for personal_sign and typed data.
15+
1016
### Changed
1117

1218
- Bump `@metamask/keyring-api` from `^23.1.0` to `^23.2.0` ([#562](https://github.com/MetaMask/accounts/pull/562))

packages/keyring-eth-ledger-bridge/jest.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ module.exports = merge(baseConfig, {
2727
coverageThreshold: {
2828
global: {
2929
branches: 93.53,
30-
functions: 98.3,
31-
lines: 97.94,
32-
statements: 97.96,
30+
functions: 97.03,
31+
lines: 97.73,
32+
statements: 97.75,
3333
},
3434
},
3535
});

packages/keyring-eth-ledger-bridge/src/ledger-bridge.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ export type LedgerSignTypedDataResponse = Awaited<
2525
ReturnType<LedgerHwAppEth['signEIP712HashedMessage']>
2626
>;
2727

28+
export type LedgerSignDelegationAuthorizationParams = {
29+
hdPath: string;
30+
chainId: number;
31+
contractAddress: string;
32+
nonce: number;
33+
};
34+
35+
// TODO: Replace with 7702 return type
36+
export type LedgerSignDelegationAuthorizationResponse = Awaited<{
37+
s: string;
38+
v: string;
39+
r: string;
40+
}>;
41+
2842
export type GetAppNameAndVersionResponse = {
2943
appName: string;
3044
version: string;
@@ -77,6 +91,10 @@ export type LedgerBridge<T extends LedgerBridgeOptions> = {
7791
params: LedgerSignTypedDataParams,
7892
): Promise<LedgerSignTypedDataResponse>;
7993

94+
deviceSignDelegationAuthorization(
95+
params: LedgerSignDelegationAuthorizationParams,
96+
): Promise<LedgerSignDelegationAuthorizationResponse>;
97+
8098
/**
8199
* Method to retrieve the name and version of the running application on the Ledger device.
82100
*

packages/keyring-eth-ledger-bridge/src/ledger-iframe-bridge.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
GetPublicKeyParams,
77
GetPublicKeyResponse,
88
LedgerBridge,
9+
LedgerSignDelegationAuthorizationParams,
10+
LedgerSignDelegationAuthorizationResponse,
911
LedgerSignMessageParams,
1012
LedgerSignMessageResponse,
1113
LedgerSignTransactionParams,
@@ -238,6 +240,14 @@ export class LedgerIframeBridge implements LedgerBridge<LedgerIframeBridgeOption
238240
);
239241
}
240242

243+
async deviceSignDelegationAuthorization(
244+
_params: LedgerSignDelegationAuthorizationParams,
245+
): Promise<LedgerSignDelegationAuthorizationResponse> {
246+
throw new Error(
247+
'Ledger: signDelegationAuthorization is not supported via iframe bridge',
248+
);
249+
}
250+
241251
async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {
242252
return this.#deviceActionMessage(
243253
IFrameMessageAction.LedgerGetAppNameAndVersion,

0 commit comments

Comments
 (0)