Skip to content

Conversation

@Akaryatrh
Copy link
Contributor

@Akaryatrh Akaryatrh commented Aug 25, 2025

Adds OneKey keyring based on OneKey libraries.


Note

Introduce @metamask/eth-onekey-keyring with OneKey Web SDK integration for account derivation and EVM signing.

  • New package: @metamask/eth-onekey-keyring
    • Implements OneKeyKeyring with HD path management, account pagination, and device passphrase handling.
    • Adds OneKeyWebBridge adapter over @onekeyfe/hd-web-sdk for public key export, transaction/message/typed-data signing, transport switching, and UI event handling.
    • Exposes types (OneKeyBridge) and entrypoints via src/index.ts.
    • Includes comprehensive unit tests for keyring and bridge, plus Jest config, TypeDoc, TS configs, and package metadata.
  • Repo updates:
    • Add package to README.md list and dependency graph.
    • Update root tsconfig.json and tsconfig.build.json references to include the new package.

Written by Cursor Bugbot for commit 8508712. This will update automatically on new commits. Configure here.

@Akaryatrh Akaryatrh requested a review from a team as a code owner August 25, 2025 13:44
@socket-security
Copy link

socket-security bot commented Aug 25, 2025

@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch from 2dc83be to a18c779 Compare August 25, 2025 13:46
@Akaryatrh Akaryatrh added the team-hardware-wallets This should be handled by the Hardware Wallets Team label Aug 25, 2025
@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

cursor[bot]

This comment was marked as outdated.

@github-actions
Copy link

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.9.0-a18c779",
  "@metamask-previews/keyring-api": "20.1.0-a18c779",
  "@metamask-previews/eth-hd-keyring": "12.1.0-a18c779",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-a18c779",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-a18c779",
  "@metamask-previews/eth-qr-keyring": "0.0.0-a18c779",
  "@metamask-previews/eth-simple-keyring": "10.0.0-a18c779",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-a18c779",
  "@metamask-previews/keyring-internal-api": "8.1.0-a18c779",
  "@metamask-previews/keyring-internal-snap-client": "6.0.0-a18c779",
  "@metamask-previews/eth-snap-keyring": "16.1.0-a18c779",
  "@metamask-previews/keyring-snap-client": "7.0.0-a18c779",
  "@metamask-previews/keyring-snap-sdk": "6.0.0-a18c779",
  "@metamask-previews/keyring-utils": "3.1.0-a18c779"
}

@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.9.0-a621908",
  "@metamask-previews/keyring-api": "20.1.0-a621908",
  "@metamask-previews/eth-hd-keyring": "12.1.0-a621908",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-a621908",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-a621908",
  "@metamask-previews/eth-qr-keyring": "0.0.0-a621908",
  "@metamask-previews/eth-simple-keyring": "10.0.0-a621908",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-a621908",
  "@metamask-previews/keyring-internal-api": "8.1.0-a621908",
  "@metamask-previews/keyring-internal-snap-client": "6.0.0-a621908",
  "@metamask-previews/eth-snap-keyring": "16.1.0-a621908",
  "@metamask-previews/keyring-snap-client": "7.0.0-a621908",
  "@metamask-previews/keyring-snap-sdk": "6.0.0-a621908",
  "@metamask-previews/keyring-utils": "3.1.0-a621908"
}

cursor[bot]

This comment was marked as outdated.

@Akaryatrh Akaryatrh mentioned this pull request Aug 26, 2025
@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.9.0-3e52ac6",
  "@metamask-previews/keyring-api": "20.1.0-3e52ac6",
  "@metamask-previews/eth-hd-keyring": "12.1.0-3e52ac6",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-3e52ac6",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-3e52ac6",
  "@metamask-previews/eth-qr-keyring": "0.0.0-3e52ac6",
  "@metamask-previews/eth-simple-keyring": "10.0.0-3e52ac6",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-3e52ac6",
  "@metamask-previews/keyring-internal-api": "8.1.0-3e52ac6",
  "@metamask-previews/keyring-internal-snap-client": "6.0.0-3e52ac6",
  "@metamask-previews/eth-snap-keyring": "16.1.0-3e52ac6",
  "@metamask-previews/keyring-snap-client": "7.0.0-3e52ac6",
  "@metamask-previews/keyring-snap-sdk": "6.0.0-3e52ac6",
  "@metamask-previews/keyring-utils": "3.1.0-3e52ac6"
}

@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

2 similar comments
@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

github-actions bot commented Sep 4, 2025

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.9.0-a4bb524",
  "@metamask-previews/keyring-api": "20.1.0-a4bb524",
  "@metamask-previews/eth-hd-keyring": "12.1.0-a4bb524",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-a4bb524",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-a4bb524",
  "@metamask-previews/eth-qr-keyring": "0.0.0-a4bb524",
  "@metamask-previews/eth-simple-keyring": "10.0.0-a4bb524",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-a4bb524",
  "@metamask-previews/keyring-internal-api": "8.1.0-a4bb524",
  "@metamask-previews/keyring-internal-snap-client": "6.0.0-a4bb524",
  "@metamask-previews/eth-snap-keyring": "16.1.0-a4bb524",
  "@metamask-previews/keyring-snap-client": "7.0.0-a4bb524",
  "@metamask-previews/keyring-snap-sdk": "6.0.0-a4bb524",
  "@metamask-previews/keyring-utils": "3.1.0-a4bb524"
}

@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

github-actions bot commented Sep 5, 2025

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.10.0-8f62d3a",
  "@metamask-previews/keyring-api": "21.0.0-8f62d3a",
  "@metamask-previews/eth-hd-keyring": "12.1.0-8f62d3a",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-8f62d3a",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-8f62d3a",
  "@metamask-previews/eth-qr-keyring": "1.1.0-8f62d3a",
  "@metamask-previews/eth-simple-keyring": "10.0.0-8f62d3a",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-8f62d3a",
  "@metamask-previews/keyring-internal-api": "9.0.0-8f62d3a",
  "@metamask-previews/keyring-internal-snap-client": "7.0.0-8f62d3a",
  "@metamask-previews/eth-snap-keyring": "17.0.0-8f62d3a",
  "@metamask-previews/keyring-snap-client": "8.0.0-8f62d3a",
  "@metamask-previews/keyring-snap-sdk": "7.0.0-8f62d3a",
  "@metamask-previews/keyring-utils": "3.1.0-8f62d3a"
}

Copy link
Contributor

@dawnseeker8 dawnseeker8 left a comment

Choose a reason for hiding this comment

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

Please change your new keyring to implement the new keyring type to support new BIP44 structure tree.

@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch 2 times, most recently from e912151 to 2ee6f90 Compare October 14, 2025 10:15
@socket-security
Copy link

socket-security bot commented Oct 14, 2025

Warning

MetaMask internal reviewing guidelines:

  • Do not ignore-all
  • Each alert has instructions on how to review if you don't know what it means. If lost, ask your Security Liaison or the supply-chain group
  • Copy-paste ignore lines for specific packages or a group of one kind with a note on what research you did to deem it safe.
    @SocketSecurity ignore npm/PACKAGE@VERSION
Action Severity Alert  (click "▶" to expand/collapse)
Warn Low
Potential code anomaly (AI signal): npm axios is 100.0% likely to have a medium risk anomaly

Notes: The code is a legitimate, self-contained throttling transformer designed for Axios-like streaming workflows. It throttles data output based on maxRate and timeWindow, preserves data integrity by splitting chunks when necessary, and emits optional progress telemetry. No malicious activity or data leakage is detected in this fragment. Security risk remains moderate due to throttling complexity and potential misconfiguration in real deployments, but the module itself does not introduce obvious security flaws.

Confidence: 1.00

Severity: 0.60

From: packages/keyring-eth-onekey/package.jsonnpm/@onekeyfe/[email protected]npm/[email protected]

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch from 2ee6f90 to f0a1825 Compare October 20, 2025 09:00
@Akaryatrh
Copy link
Contributor Author

@SocketSecurity ignore npm/[email protected]

@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch from f0a1825 to 7d43e97 Compare October 20, 2025 09:14
@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.12.0-7d43e97",
  "@metamask-previews/keyring-api": "21.1.0-7d43e97",
  "@metamask-previews/eth-hd-keyring": "13.0.0-7d43e97",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-7d43e97",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-7d43e97",
  "@metamask-previews/eth-qr-keyring": "1.1.0-7d43e97",
  "@metamask-previews/eth-simple-keyring": "11.0.0-7d43e97",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-7d43e97",
  "@metamask-previews/keyring-internal-api": "9.1.0-7d43e97",
  "@metamask-previews/keyring-internal-snap-client": "7.2.0-7d43e97",
  "@metamask-previews/eth-snap-keyring": "17.3.0-7d43e97",
  "@metamask-previews/keyring-snap-client": "8.1.0-7d43e97",
  "@metamask-previews/keyring-snap-sdk": "7.1.0-7d43e97",
  "@metamask-previews/keyring-utils": "3.1.0-7d43e97"
}

Comment on lines 137 to 155
page = 0;

perPage = 5;

unlockedAccount = 0;

hdk = new HDKey();

accounts: readonly Hex[] = [];

accountDetails: Record<string, AccountDetails> = {};

passphraseState: string | undefined;

hdPath = defaultHdPath;

network: NetworkApiUrls = NetworkApiUrls.Mainnet;

implementFullBIP44 = false;
Copy link
Member

Choose a reason for hiding this comment

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

Can we make these properties sharp, and readonly where possible?

Comment on lines +233 to +194
lock(): void {
this.hdk = new HDKey();
}

isUnlocked(): boolean {
return Boolean(this.hdk?.publicKey);
}
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this locking mechanism internal to the keyring? What does this lock represent?

Choose a reason for hiding this comment

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

lock, isUnlocked
These two are designed to optimize the user experience of our hardware passphrase functionality.
Without them, users would need to re-enter the passphrase every time. We lock when entering the connect wallet page, then have the device re-enter the passphrase. This ensures that scenarios like address pagination won't trigger passphrase re-entry.

Copy link
Member

@mikesposito mikesposito Dec 4, 2025

Choose a reason for hiding this comment

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

hmm the only thing I see this doing is removing the cached HD public key coming from the device. Though .lock is not a common method that other hardware keyrings have, and we'd have to add specific code on clients to be call this function on the OneKey keyring. I was wondering if we really need this mechanism instead of just relying on usual patterns we have on other keyrings, where the "lock" is coming from KeyringController in the form of destroying keyring instances altogether

return Promise.resolve();
}

getModel(): string | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is/will this method used somewhere? If not, it can be removed.

Choose a reason for hiding this comment

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

used to distinguish equipment models.

}
const signature = addHexPrefix(response.payload.signature);
// eslint-disable-next-line promise/no-multiple-resolved
resolve(signature);
Copy link

Choose a reason for hiding this comment

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

Bug: Missing return after reject causes double promise resolution

In signPersonalMessage, when the address verification fails (lines 410-414), reject() is called but execution continues without a return statement. This causes resolve(signature) to also be called on line 418. The // eslint-disable-next-line promise/no-multiple-resolved comment explicitly acknowledges this issue. While Promise semantics cause the first call (reject) to take effect, the control flow is broken—the code after reject() still runs unnecessarily. The similar signTypedData method correctly handles this case by using throw instead, which properly exits the function.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

Cursor is right here, you should remove the // eslint-disable-next-line and put the resolve in a else {} block.

@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch from be5d34b to a9761e5 Compare December 1, 2025 09:50
@Akaryatrh Akaryatrh force-pushed the feat/onekey-keyring branch from a9761e5 to 8508712 Compare December 1, 2025 09:53
@Akaryatrh
Copy link
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link

github-actions bot commented Dec 1, 2025

Preview builds have been published. See these instructions (from the core monorepo) for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-api": "0.12.0-8508712",
  "@metamask-previews/keyring-api": "21.3.0-8508712",
  "@metamask-previews/eth-hd-keyring": "13.0.0-8508712",
  "@metamask-previews/eth-ledger-bridge-keyring": "11.1.2-8508712",
  "@metamask-previews/eth-onekey-keyring": "0.1.0-8508712",
  "@metamask-previews/eth-qr-keyring": "1.1.0-8508712",
  "@metamask-previews/eth-simple-keyring": "11.0.0-8508712",
  "@metamask-previews/eth-trezor-keyring": "9.0.0-8508712",
  "@metamask-previews/keyring-internal-api": "9.1.1-8508712",
  "@metamask-previews/keyring-internal-snap-client": "8.0.1-8508712",
  "@metamask-previews/eth-snap-keyring": "18.0.2-8508712",
  "@metamask-previews/keyring-snap-client": "8.1.1-8508712",
  "@metamask-previews/keyring-snap-sdk": "7.1.1-8508712",
  "@metamask-previews/keyring-utils": "3.1.0-8508712"
}

reject(new Error('signature doesnt match the right address'));
}
// eslint-disable-next-line promise/no-multiple-resolved
resolve(signature);
Copy link

Choose a reason for hiding this comment

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

Bug: Missing return after reject causes dual promise settlement

In signPersonalMessage, when the recovered address doesn't match the expected account, reject() is called but execution continues without returning. This causes resolve(signature) on line 427 to also be called. The eslint-disable-next-line promise/no-multiple-resolved comment explicitly suppresses the linter warning about this issue rather than fixing it. While Promise semantics make only the first settlement effective, calling both reject() and resolve() is a control flow error indicating the code doesn't properly stop execution after detecting the address mismatch.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

async dispose(): Promise<void> {
this.sdk?.dispose();
return Promise.resolve();
}
Copy link

Choose a reason for hiding this comment

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

Bug: Dispose leaves bridge in inconsistent reinitialization state

The dispose() method calls this.sdk?.dispose() but doesn't reset isSDKInitialized or sdk. When keyring.destroy() calls bridge.dispose(), the bridge is left in an inconsistent state where isSDKInitialized remains true and sdk still references the disposed SDK. If init() is called afterward, it returns early because isSDKInitialized is true, preventing reinitialization. Subsequent operations will then use the disposed SDK. The destroy() method properly resets state but is never called by the keyring.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

Cursor's comment here make sense. We should add this.isSDKInitialized = false;.

Comment on lines +135 to +137
return await this.sdk
.evmGetPublicKey('', '', { ...params, skipPassphraseCheck: true })
.then((result) => {
Copy link
Member

Choose a reason for hiding this comment

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

Can we avoid mixing .then().catch() with async/awaits? Can we use async/await only to improve readability?

Choose a reason for hiding this comment

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

ok, I'll make some revisions.

},
};
}
return await this.sdk.getPassphraseState('').then((result) => {
Copy link
Member

Choose a reason for hiding this comment

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

similar to my other comment, can we use a more consistent pattern with promises?

...params,
skipPassphraseCheck: true,
})
.then((result) => {
Copy link
Member

Choose a reason for hiding this comment

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

similar to other comments, can we use async/await only?

...params,
skipPassphraseCheck: true,
})
.then((result) => {
Copy link
Member

Choose a reason for hiding this comment

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

Can we use async/await?

...params,
skipPassphraseCheck: true,
})
.then((result) => {
Copy link
Member

Choose a reason for hiding this comment

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

can we use async/await?

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

Labels

team-hardware-wallets This should be handled by the Hardware Wallets Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants