From e0353bdfd5e1d2866d3e089bc5de51cef2351f24 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Tue, 21 Jan 2025 17:29:26 +0100 Subject: [PATCH 1/8] release: 21.0.0 (#155) # Description This is the release candidate for version 21.0.0. See the CHANGELOGs for more details. --- package.json | 2 +- packages/keyring-api/CHANGELOG.md | 14 +++++++++++++- packages/keyring-api/package.json | 2 +- packages/keyring-internal-api/CHANGELOG.md | 9 ++++++++- packages/keyring-internal-api/package.json | 2 +- .../keyring-internal-snap-client/CHANGELOG.md | 15 ++++++++++++++- .../keyring-internal-snap-client/package.json | 2 +- packages/keyring-snap-bridge/CHANGELOG.md | 9 ++++++++- packages/keyring-snap-bridge/package.json | 2 +- packages/keyring-snap-client/CHANGELOG.md | 14 +++++++++++++- packages/keyring-snap-client/package.json | 2 +- packages/keyring-snap-sdk/CHANGELOG.md | 9 ++++++++- packages/keyring-snap-sdk/package.json | 2 +- packages/keyring-utils/CHANGELOG.md | 10 +++++++++- packages/keyring-utils/package.json | 2 +- 15 files changed, 81 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 79b52923..51204e8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/accounts-monorepo", - "version": "20.0.0", + "version": "21.0.0", "private": true, "description": "Monorepo for MetaMask accounts related packages", "repository": { diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index a473f9f1..c37f3ea0 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [14.0.0] + +### Added + +- Add `listAccountAssets` keyring method ([#148](https://github.com/MetaMask/accounts/pull/148)) + +### Changed + +- **BREAKING:** Make `CaipAssetType` type more restritive ([#150](https://github.com/MetaMask/accounts/pull/150)) + - It used to be a `string` but it has been restricted with a template literal type that matches CAIP-19 asset type. + ## [13.0.0] ### Added @@ -466,7 +477,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SnapController keyring client. It is intended to be used by MetaMask to talk to the snap. - Helper functions to create keyring handler in the snap. -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@13.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@14.0.0...HEAD +[14.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@13.0.0...@metamask/keyring-api@14.0.0 [13.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@12.0.0...@metamask/keyring-api@13.0.0 [12.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@11.1.0...@metamask/keyring-api@12.0.0 [11.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@11.0.0...@metamask/keyring-api@11.1.0 diff --git a/packages/keyring-api/package.json b/packages/keyring-api/package.json index 3a9832b5..6948e7cf 100644 --- a/packages/keyring-api/package.json +++ b/packages/keyring-api/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-api", - "version": "13.0.0", + "version": "14.0.0", "description": "MetaMask Keyring API", "keywords": [ "metamask", diff --git a/packages/keyring-internal-api/CHANGELOG.md b/packages/keyring-internal-api/CHANGELOG.md index cddb1bc5..740512bb 100644 --- a/packages/keyring-internal-api/CHANGELOG.md +++ b/packages/keyring-internal-api/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.0.1] + +### Changed + +- Bump `@metamask/keyring-api` from `^13.0.0` to `^14.0.0` ([#155](https://github.com/MetaMask/accounts/pull/155)) + ## [2.0.0] ### Changed @@ -29,7 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.1...HEAD +[2.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.0...@metamask/keyring-internal-api@2.0.1 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@1.1.0...@metamask/keyring-internal-api@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@1.0.0...@metamask/keyring-internal-api@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-internal-api@1.0.0 diff --git a/packages/keyring-internal-api/package.json b/packages/keyring-internal-api/package.json index 25e32834..5483db50 100644 --- a/packages/keyring-internal-api/package.json +++ b/packages/keyring-internal-api/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-internal-api", - "version": "2.0.0", + "version": "2.0.1", "description": "MetaMask Keyring Internal API", "keywords": [ "metamask", diff --git a/packages/keyring-internal-snap-client/CHANGELOG.md b/packages/keyring-internal-snap-client/CHANGELOG.md index b3db6cdb..761e3b04 100644 --- a/packages/keyring-internal-snap-client/CHANGELOG.md +++ b/packages/keyring-internal-snap-client/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.0] + +### Added + +- Add `listAccountAssets` keyring method ([#148](https://github.com/MetaMask/accounts/pull/148)) + - This is inherited from the `KeyringClient` changes. + +### Changed + +- **BREAKING:** Bump `@metamask/keyring-api` from `^13.0.0` to `^14.0.0` ([#155](https://github.com/MetaMask/accounts/pull/155)) + - The `CaipAssetType` is now more restrictive which affects the existing `getAccountBalances` method. + ## [2.0.0] ### Changed @@ -33,7 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@2.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@3.0.0...HEAD +[3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@2.0.0...@metamask/keyring-internal-snap-client@3.0.0 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@1.1.0...@metamask/keyring-internal-snap-client@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@1.0.0...@metamask/keyring-internal-snap-client@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-internal-snap-client@1.0.0 diff --git a/packages/keyring-internal-snap-client/package.json b/packages/keyring-internal-snap-client/package.json index a50f9b48..ec522ea5 100644 --- a/packages/keyring-internal-snap-client/package.json +++ b/packages/keyring-internal-snap-client/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-internal-snap-client", - "version": "2.0.0", + "version": "3.0.0", "description": "MetaMask Keyring Snap internal clients", "keywords": [ "metamask", diff --git a/packages/keyring-snap-bridge/CHANGELOG.md b/packages/keyring-snap-bridge/CHANGELOG.md index c42a897a..7673377e 100644 --- a/packages/keyring-snap-bridge/CHANGELOG.md +++ b/packages/keyring-snap-bridge/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [8.1.1] + +### Changed + +- Bump `@metamask/keyring-api` from `^13.0.0` to `^14.0.0` ([#155](https://github.com/MetaMask/accounts/pull/155)) + ## [8.1.0] ### Added @@ -410,7 +416,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release. -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.1...HEAD +[8.1.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.0...@metamask/eth-snap-keyring@8.1.1 [8.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.0.0...@metamask/eth-snap-keyring@8.1.0 [8.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@7.1.0...@metamask/eth-snap-keyring@8.0.0 [7.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@7.0.0...@metamask/eth-snap-keyring@7.1.0 diff --git a/packages/keyring-snap-bridge/package.json b/packages/keyring-snap-bridge/package.json index 70e94867..0255c222 100644 --- a/packages/keyring-snap-bridge/package.json +++ b/packages/keyring-snap-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/eth-snap-keyring", - "version": "8.1.0", + "version": "8.1.1", "description": "Snaps keyring bridge.", "repository": { "type": "git", diff --git a/packages/keyring-snap-client/CHANGELOG.md b/packages/keyring-snap-client/CHANGELOG.md index 009cb80a..245e6176 100644 --- a/packages/keyring-snap-client/CHANGELOG.md +++ b/packages/keyring-snap-client/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.0] + +### Added + +- Add `listAccountAssets` keyring method ([#148](https://github.com/MetaMask/accounts/pull/148)) + +### Changed + +- **BREAKING:** Bump `@metamask/keyring-api` from `^13.0.0` to `^14.0.0` ([#155](https://github.com/MetaMask/accounts/pull/155)) + - The `CaipAssetType` is now more restrictive which affects the existing `getAccountBalances` method. + ## [2.0.0] ### Changed @@ -29,7 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@2.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@3.0.0...HEAD +[3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@2.0.0...@metamask/keyring-snap-client@3.0.0 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@1.1.0...@metamask/keyring-snap-client@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@1.0.0...@metamask/keyring-snap-client@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-snap-client@1.0.0 diff --git a/packages/keyring-snap-client/package.json b/packages/keyring-snap-client/package.json index ef364ac4..4891074a 100644 --- a/packages/keyring-snap-client/package.json +++ b/packages/keyring-snap-client/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-snap-client", - "version": "2.0.0", + "version": "3.0.0", "description": "MetaMask Keyring Snap clients", "keywords": [ "metamask", diff --git a/packages/keyring-snap-sdk/CHANGELOG.md b/packages/keyring-snap-sdk/CHANGELOG.md index f9b62743..3f14a028 100644 --- a/packages/keyring-snap-sdk/CHANGELOG.md +++ b/packages/keyring-snap-sdk/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.0] + +### Added + +- Add support of `listAccountAssets` keyring method ([#148](https://github.com/MetaMask/accounts/pull/148)) + ## [2.0.0] ### Changed @@ -29,7 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-sdk@2.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-sdk@2.1.0...HEAD +[2.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-sdk@2.0.0...@metamask/keyring-snap-sdk@2.1.0 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-sdk@1.1.0...@metamask/keyring-snap-sdk@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-sdk@1.0.0...@metamask/keyring-snap-sdk@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-snap-sdk@1.0.0 diff --git a/packages/keyring-snap-sdk/package.json b/packages/keyring-snap-sdk/package.json index 24df5c01..50b1f136 100644 --- a/packages/keyring-snap-sdk/package.json +++ b/packages/keyring-snap-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-snap-sdk", - "version": "2.0.0", + "version": "2.1.0", "description": "MetaMask Keyring Snap SDK", "keywords": [ "metamask", diff --git a/packages/keyring-utils/CHANGELOG.md b/packages/keyring-utils/CHANGELOG.md index ba1a4c2b..a80dccb6 100644 --- a/packages/keyring-utils/CHANGELOG.md +++ b/packages/keyring-utils/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0] + +### Changed + +- Add generic type in `definePattern` ([#150](https://github.com/MetaMask/accounts/pull/150)) + - It allows to use template literal type that matches the pattern. + ## [1.1.0] ### Added @@ -25,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.1.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.2.0...HEAD +[1.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.1.0...@metamask/keyring-utils@1.2.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.0.0...@metamask/keyring-utils@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-utils@1.0.0 diff --git a/packages/keyring-utils/package.json b/packages/keyring-utils/package.json index 6615e525..97ba7d9b 100644 --- a/packages/keyring-utils/package.json +++ b/packages/keyring-utils/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-utils", - "version": "1.1.0", + "version": "1.2.0", "description": "MetaMask Keyring utils", "keywords": [ "metamask", From 2bdc87a8a1475e553118d943da07941a4530a6ce Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Tue, 21 Jan 2025 17:46:27 +0100 Subject: [PATCH 2/8] feat!: use `Messenger` instead of `SnapsController` (#152) Introducing the concept of `Messenger` (messaging system that we use in our `core` controllers) to break the runtime dependency we have with the `SnapController`. We will also use this new `Messenger` later when the Snap keyring will re-forward some Snap account events to some other controllers. This is **BREAKING** because of the removal of the `KeyringSnapControllerClient` and because the `SnapKeyring`'s constructor now requires a `Messenger` object instead of the `SnapController`. --- .../keyring-internal-snap-client/package.json | 14 +- .../src/KeyringInternalSnapClient.test.ts | 84 +++++++ .../src/KeyringInternalSnapClient.ts | 124 ++++++++++ .../src/KeyringSnapControllerClient.test.ts | 83 ------- .../src/KeyringSnapControllerClient.ts | 115 --------- .../keyring-internal-snap-client/src/index.ts | 2 +- packages/keyring-snap-bridge/package.json | 14 +- .../src/SnapKeyring.test.ts | 220 +++++++++++------- .../keyring-snap-bridge/src/SnapKeyring.ts | 35 ++- .../src/SnapKeyringMessenger.ts | 14 ++ yarn.lock | 19 +- 11 files changed, 405 insertions(+), 319 deletions(-) create mode 100644 packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.test.ts create mode 100644 packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.ts delete mode 100644 packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.test.ts delete mode 100644 packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.ts create mode 100644 packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts diff --git a/packages/keyring-internal-snap-client/package.json b/packages/keyring-internal-snap-client/package.json index ec522ea5..288c6915 100644 --- a/packages/keyring-internal-snap-client/package.json +++ b/packages/keyring-internal-snap-client/package.json @@ -45,19 +45,18 @@ "test:watch": "jest --watch" }, "dependencies": { + "@metamask/base-controller": "^7.1.1", "@metamask/keyring-api": "workspace:^", "@metamask/keyring-snap-client": "workspace:^", - "@metamask/keyring-utils": "workspace:^", - "@metamask/snaps-controllers": "^9.10.0", - "@metamask/snaps-sdk": "^6.7.0", - "@metamask/snaps-utils": "^8.3.0", - "webextension-polyfill": "^0.12.0" + "@metamask/keyring-utils": "workspace:^" }, "devDependencies": { "@lavamoat/allow-scripts": "^3.2.1", "@lavamoat/preinstall-always-fail": "^2.1.0", "@metamask/auto-changelog": "^3.4.4", - "@metamask/providers": "^18.3.1", + "@metamask/snaps-controllers": "^9.10.0", + "@metamask/snaps-sdk": "^6.7.0", + "@metamask/snaps-utils": "^8.3.0", "@metamask/utils": "^11.0.1", "@ts-bridge/cli": "^0.6.1", "@types/jest": "^29.5.12", @@ -73,9 +72,6 @@ "typedoc": "^0.25.13", "typescript": "~5.6.3" }, - "peerDependencies": { - "@metamask/providers": "^18.3.1" - }, "engines": { "node": "^18.18 || >=20" }, diff --git a/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.test.ts b/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.test.ts new file mode 100644 index 00000000..891ed4fa --- /dev/null +++ b/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.test.ts @@ -0,0 +1,84 @@ +import type { KeyringAccount } from '@metamask/keyring-api'; +import type { SnapId } from '@metamask/snaps-sdk'; + +import { + KeyringInternalSnapClient, + type KeyringInternalSnapClientMessenger, +} from './KeyringInternalSnapClient'; + +describe('KeyringInternalSnapClient', () => { + const snapId = 'local:localhost:3000' as SnapId; + + const accountsList: KeyringAccount[] = [ + { + id: '13f94041-6ae6-451f-a0fe-afdd2fda18a7', + address: '0xE9A74AACd7df8112911ca93260fC5a046f8a64Ae', + options: {}, + methods: [], + scopes: ['eip155'], + type: 'eip155:eoa', + }, + ]; + + const messenger = { + call: jest.fn(), + }; + + describe('listAccounts', () => { + const request = { + snapId, + origin: 'metamask', + handler: 'onKeyringRequest', + request: { + id: expect.any(String), + jsonrpc: '2.0', + method: 'keyring_listAccounts', + }, + }; + + it('calls the listAccounts method and return the result', async () => { + const client = new KeyringInternalSnapClient({ + messenger: messenger as unknown as KeyringInternalSnapClientMessenger, + snapId, + }); + + messenger.call.mockResolvedValue(accountsList); + const accounts = await client.listAccounts(); + expect(messenger.call).toHaveBeenCalledWith( + 'SnapController:handleRequest', + request, + ); + expect(accounts).toStrictEqual(accountsList); + }); + + it('calls the listAccounts method and return the result (withSnapId)', async () => { + const client = new KeyringInternalSnapClient({ + messenger: messenger as unknown as KeyringInternalSnapClientMessenger, + }); + + messenger.call.mockResolvedValue(accountsList); + const accounts = await client.withSnapId(snapId).listAccounts(); + expect(messenger.call).toHaveBeenCalledWith( + 'SnapController:handleRequest', + request, + ); + expect(accounts).toStrictEqual(accountsList); + }); + + it('calls the default snapId value ("undefined")', async () => { + const client = new KeyringInternalSnapClient({ + messenger: messenger as unknown as KeyringInternalSnapClientMessenger, + }); + + messenger.call.mockResolvedValue(accountsList); + await client.listAccounts(); + expect(messenger.call).toHaveBeenCalledWith( + 'SnapController:handleRequest', + { + ...request, + snapId: 'undefined', + }, + ); + }); + }); +}); diff --git a/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.ts b/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.ts new file mode 100644 index 00000000..da1bdf04 --- /dev/null +++ b/packages/keyring-internal-snap-client/src/KeyringInternalSnapClient.ts @@ -0,0 +1,124 @@ +import type { RestrictedControllerMessenger } from '@metamask/base-controller'; +import { KeyringClient, type Sender } from '@metamask/keyring-snap-client'; +import type { JsonRpcRequest } from '@metamask/keyring-utils'; +import type { HandleSnapRequest } from '@metamask/snaps-controllers'; +import type { SnapId } from '@metamask/snaps-sdk'; +import type { HandlerType } from '@metamask/snaps-utils'; +import type { Json } from '@metamask/utils'; + +// We only need to dispatch Snap request to the Snaps controller for now. +type AllowedActions = HandleSnapRequest; + +/** + * A restricted-`Messenger` used by `KeyringInternalSnapClient` to dispatch + * internal Snap requests. + */ +export type KeyringInternalSnapClientMessenger = RestrictedControllerMessenger< + 'KeyringInternalSnapClient', + AllowedActions, + never, + AllowedActions['type'], + never +>; + +/** + * Implementation of the `Sender` interface that can be used to send requests + * to a Snap through a `Messenger`. + */ +class SnapControllerMessengerSender implements Sender { + readonly #snapId: SnapId; + + readonly #origin: string; + + readonly #messenger: KeyringInternalSnapClientMessenger; + + readonly #handler: HandlerType; + + /** + * Create a new instance of `SnapControllerSender`. + * + * @param messenger - The `Messenger` instance used when dispatching controllers actions. + * @param snapId - The ID of the Snap to use. + * @param origin - The sender's origin. + * @param handler - The handler type. + */ + constructor( + messenger: KeyringInternalSnapClientMessenger, + snapId: SnapId, + origin: string, + handler: HandlerType, + ) { + this.#messenger = messenger; + this.#snapId = snapId; + this.#origin = origin; + this.#handler = handler; + } + + /** + * Send a request to the Snap and return the response. + * + * @param request - JSON-RPC request to send to the Snap. + * @returns A promise that resolves to the response of the request. + */ + async send(request: JsonRpcRequest): Promise { + return this.#messenger.call('SnapController:handleRequest', { + snapId: this.#snapId, + origin: this.#origin, + handler: this.#handler, + request, + }) as Promise; + } +} + +/** + * A `KeyringClient` that allows the communication with a Snap through a + * `Messenger`. + */ +export class KeyringInternalSnapClient extends KeyringClient { + readonly #messenger: KeyringInternalSnapClientMessenger; + + /** + * Create a new instance of `KeyringInternalSnapClient`. + * + * The `handlerType` argument has a hard-coded default `string` value instead + * of a `HandlerType` value to prevent the `@metamask/snaps-utils` module + * from being required at runtime. + * + * @param args - Constructor arguments. + * @param args.messenger - The `KeyringInternalSnapClientMessenger` instance to use. + * @param args.snapId - The ID of the Snap to use (default: `'undefined'`). + * @param args.origin - The sender's origin (default: `'metamask'`). + * @param args.handler - The handler type (default: `'onKeyringRequest'`). + */ + constructor({ + messenger, + snapId = 'undefined' as SnapId, + origin = 'metamask', + handler = 'onKeyringRequest' as HandlerType, + }: { + messenger: KeyringInternalSnapClientMessenger; + snapId?: SnapId; + origin?: string; + handler?: HandlerType; + }) { + super( + new SnapControllerMessengerSender(messenger, snapId, origin, handler), + ); + this.#messenger = messenger; + } + + /** + * Create a new instance of `KeyringInternalSnapClient` with the specified + * `snapId`. + * + * @param snapId - The ID of the Snap to use in the new instance. + * @returns A new instance of `KeyringInternalSnapClient` with the + * specified Snap ID. + */ + withSnapId(snapId: SnapId): KeyringInternalSnapClient { + return new KeyringInternalSnapClient({ + messenger: this.#messenger, + snapId, + }); + } +} diff --git a/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.test.ts b/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.test.ts deleted file mode 100644 index a9d73773..00000000 --- a/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { KeyringAccount } from '@metamask/keyring-api'; -import type { SnapController } from '@metamask/snaps-controllers'; -import type { SnapId } from '@metamask/snaps-sdk'; - -import { KeyringSnapControllerClient } from './KeyringSnapControllerClient'; - -describe('KeyringSnapControllerClient', () => { - const snapId = 'local:localhost:3000' as SnapId; - - const accountsList: KeyringAccount[] = [ - { - id: '13f94041-6ae6-451f-a0fe-afdd2fda18a7', - address: '0xE9A74AACd7df8112911ca93260fC5a046f8a64Ae', - options: {}, - methods: [], - scopes: ['eip155'], - type: 'eip155:eoa', - }, - ]; - - const controller = { - handleRequest: jest.fn(), - }; - - describe('listAccounts', () => { - const request = { - snapId, - origin: 'metamask', - handler: 'onKeyringRequest', - request: { - id: expect.any(String), - jsonrpc: '2.0', - method: 'keyring_listAccounts', - }, - }; - - it('should call the listAccounts method and return the result', async () => { - const client = new KeyringSnapControllerClient({ - controller: controller as unknown as SnapController, - snapId, - }); - - controller.handleRequest.mockResolvedValue(accountsList); - const accounts = await client.listAccounts(); - expect(controller.handleRequest).toHaveBeenCalledWith(request); - expect(accounts).toStrictEqual(accountsList); - }); - - it('should call the listAccounts method and return the result (withSnapId)', async () => { - const client = new KeyringSnapControllerClient({ - controller: controller as unknown as SnapController, - }); - - controller.handleRequest.mockResolvedValue(accountsList); - const accounts = await client.withSnapId(snapId).listAccounts(); - expect(controller.handleRequest).toHaveBeenCalledWith(request); - expect(accounts).toStrictEqual(accountsList); - }); - - it('should call the default snapId value ("undefined")', async () => { - const client = new KeyringSnapControllerClient({ - controller: controller as unknown as SnapController, - }); - - controller.handleRequest.mockResolvedValue(accountsList); - await client.listAccounts(); - expect(controller.handleRequest).toHaveBeenCalledWith({ - ...request, - snapId: 'undefined', - }); - }); - }); - - describe('getController', () => { - it('should return the controller', () => { - const client = new KeyringSnapControllerClient({ - controller: controller as unknown as SnapController, - }); - - expect(client.getController()).toBe(controller); - }); - }); -}); diff --git a/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.ts b/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.ts deleted file mode 100644 index c5d8d3b0..00000000 --- a/packages/keyring-internal-snap-client/src/KeyringSnapControllerClient.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { KeyringClient, type Sender } from '@metamask/keyring-snap-client'; -import type { JsonRpcRequest } from '@metamask/keyring-utils'; -import type { SnapController } from '@metamask/snaps-controllers'; -import type { SnapId } from '@metamask/snaps-sdk'; -import type { HandlerType } from '@metamask/snaps-utils'; -import type { Json } from '@metamask/utils'; - -/** - * Implementation of the `Sender` interface that can be used to send requests - * to a snap through a `SnapController`. - */ -class SnapControllerSender implements Sender { - readonly #snapId: SnapId; - - readonly #origin: string; - - readonly #controller: SnapController; - - readonly #handler: HandlerType; - - /** - * Create a new instance of `SnapControllerSender`. - * - * @param controller - The `SnapController` instance to send requests to. - * @param snapId - The ID of the snap to use. - * @param origin - The sender's origin. - * @param handler - The handler type. - */ - constructor( - controller: SnapController, - snapId: SnapId, - origin: string, - handler: HandlerType, - ) { - this.#controller = controller; - this.#snapId = snapId; - this.#origin = origin; - this.#handler = handler; - } - - /** - * Send a request to the snap and return the response. - * - * @param request - JSON-RPC request to send to the snap. - * @returns A promise that resolves to the response of the request. - */ - async send(request: JsonRpcRequest): Promise { - return this.#controller.handleRequest({ - snapId: this.#snapId, - origin: this.#origin, - handler: this.#handler, - request, - }) as Promise; - } -} - -/** - * A `KeyringClient` that allows the communication with a snap through the - * `SnapController`. - */ -export class KeyringSnapControllerClient extends KeyringClient { - readonly #controller: SnapController; - - /** - * Create a new instance of `KeyringSnapControllerClient`. - * - * The `handlerType` argument has a hard-coded default `string` value instead - * of a `HandlerType` value to prevent the `@metamask/snaps-utils` module - * from being required at runtime. - * - * @param args - Constructor arguments. - * @param args.controller - The `SnapController` instance to use. - * @param args.snapId - The ID of the snap to use (default: `'undefined'`). - * @param args.origin - The sender's origin (default: `'metamask'`). - * @param args.handler - The handler type (default: `'onKeyringRequest'`). - */ - constructor({ - controller, - snapId = 'undefined' as SnapId, - origin = 'metamask', - handler = 'onKeyringRequest' as HandlerType, - }: { - controller: SnapController; - snapId?: SnapId; - origin?: string; - handler?: HandlerType; - }) { - super(new SnapControllerSender(controller, snapId, origin, handler)); - this.#controller = controller; - } - - /** - * Create a new instance of `KeyringSnapControllerClient` with the specified - * `snapId`. - * - * @param snapId - The ID of the snap to use in the new instance. - * @returns A new instance of `KeyringSnapControllerClient` with the - * specified snap ID. - */ - withSnapId(snapId: SnapId): KeyringSnapControllerClient { - return new KeyringSnapControllerClient({ - controller: this.#controller, - snapId, - }); - } - - /** - * Get the `SnapController` instance used by this client. - * - * @returns The `SnapController` instance used by this client. - */ - getController(): SnapController { - return this.#controller; - } -} diff --git a/packages/keyring-internal-snap-client/src/index.ts b/packages/keyring-internal-snap-client/src/index.ts index bd358351..cbd73172 100644 --- a/packages/keyring-internal-snap-client/src/index.ts +++ b/packages/keyring-internal-snap-client/src/index.ts @@ -1 +1 @@ -export * from './KeyringSnapControllerClient'; +export * from './KeyringInternalSnapClient'; diff --git a/packages/keyring-snap-bridge/package.json b/packages/keyring-snap-bridge/package.json index 0255c222..996dcf6b 100644 --- a/packages/keyring-snap-bridge/package.json +++ b/packages/keyring-snap-bridge/package.json @@ -38,25 +38,24 @@ }, "dependencies": { "@ethereumjs/tx": "^4.2.0", + "@metamask/base-controller": "^7.1.1", "@metamask/eth-sig-util": "^8.1.2", "@metamask/keyring-api": "workspace:^", "@metamask/keyring-internal-api": "workspace:^", "@metamask/keyring-internal-snap-client": "workspace:^", "@metamask/keyring-utils": "workspace:^", - "@metamask/snaps-controllers": "^9.10.0", - "@metamask/snaps-sdk": "^6.7.0", - "@metamask/snaps-utils": "^8.3.0", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.0.1", "@types/uuid": "^9.0.8", - "uuid": "^9.0.1", - "webextension-polyfill": "^0.12.0" + "uuid": "^9.0.1" }, "devDependencies": { "@lavamoat/allow-scripts": "^3.2.1", "@lavamoat/preinstall-always-fail": "^2.1.0", "@metamask/auto-changelog": "^3.4.4", - "@metamask/providers": "^18.3.1", + "@metamask/snaps-controllers": "^9.10.0", + "@metamask/snaps-sdk": "^6.7.0", + "@metamask/snaps-utils": "^8.3.0", "@ts-bridge/cli": "^0.6.1", "@types/jest": "^29.5.12", "@types/node": "^20.12.12", @@ -71,8 +70,7 @@ "typescript": "~5.6.3" }, "peerDependencies": { - "@metamask/keyring-api": "workspace:^", - "@metamask/providers": "^18.3.1" + "@metamask/keyring-api": "workspace:^" }, "engines": { "node": "^18.18 || >=20" diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts index ebebdea1..f53e3499 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts @@ -1,4 +1,5 @@ import { TransactionFactory } from '@ethereumjs/tx'; +import { ControllerMessenger } from '@metamask/base-controller'; import { SignTypedDataVersion } from '@metamask/eth-sig-util'; import type { KeyringAccount, @@ -19,7 +20,6 @@ import { BtcScopes, SolScopes, } from '@metamask/keyring-api'; -import type { SnapController } from '@metamask/snaps-controllers'; import type { SnapId } from '@metamask/snaps-sdk'; import { toCaipChainId } from '@metamask/utils'; @@ -27,6 +27,11 @@ import type { KeyringState } from '.'; import { SnapKeyring } from '.'; import type { KeyringAccountV1 } from './account'; import { migrateAccountV1, getScopesForAccountV1 } from './migrations'; +import type { + SnapKeyringAllowedActions, + SnapKeyringAllowedEvents, + SnapKeyringMessenger, +} from './SnapKeyringMessenger'; const regexForUUIDInRequiredSyncErrorMessage = /Request '[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}' to snap 'local:snap.mock' is pending and noPending is true/u; @@ -58,12 +63,56 @@ function noScopes(account: KeyringAccount): KeyringAccountV1 { return accountV1; } +/* +class MockMessenger { + readonly #messenger: SnapKeyringMessenger; + + get: jest.Mock = jest.fn(); + + handleRequest: jest.Mock = jest.fn(); + + constructor( + messenger: ControllerMessenger< + SnapKeyringAllowedActions, + SnapKeyringAllowedEvents + >, + ) { + messenger.registerActionHandler('SnapController:get', this.get); + messenger.registerActionHandler( + 'SnapController:handleRequest', + this.handleRequest, + ); + + this.#messenger = messenger.getRestricted({ + name: 'MockSnapKeyringMessenger', + allowedEvents: [], + allowedActions: ['SnapController:get', 'SnapController:handleRequest'], + }); + } + + getMessenger(): SnapKeyringMessenger { + return this.#messenger; + } + + call(action: string, ...args: any): unknown { + switch (action) { + case 'SnapController:get': + return this.get(...args); + case 'SnapController:handleRequest': + return this.handleRequest(...args); + default: + throw new Error(`Unexpected action call: ${action}`); + } + } +} +*/ + describe('SnapKeyring', () => { let keyring: SnapKeyring; - const mockSnapController = { - handleRequest: jest.fn(), + const mockMessenger = { get: jest.fn(), + handleRequest: jest.fn(), }; const mockCallbacks = { @@ -174,11 +223,31 @@ describe('SnapKeyring', () => { chainId: '1', }; + // Fake the ControllerMessenger and registers all mock actions here: + const controllerMessenger: ControllerMessenger< + SnapKeyringAllowedActions, + SnapKeyringAllowedEvents + > = new ControllerMessenger(); + controllerMessenger.registerActionHandler( + 'SnapController:get', + mockMessenger.get, + ); + controllerMessenger.registerActionHandler( + 'SnapController:handleRequest', + mockMessenger.handleRequest, + ); + + // Now extracts a rectricted messenger for the Snap keyring only. + const mockSnapKeyringMessenger: SnapKeyringMessenger = + controllerMessenger.getRestricted({ + name: 'MockSnapKeyringMessenger', + allowedEvents: [], + allowedActions: ['SnapController:get', 'SnapController:handleRequest'], + }); + beforeEach(async () => { - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); + mockCallbacks.addAccount.mockImplementation( async ( _address, @@ -190,8 +259,11 @@ describe('SnapKeyring', () => { await handleUserInput(true); }, ); + + mockMessenger.get.mockReset(); + mockMessenger.handleRequest.mockReset(); for (const account of accounts) { - mockSnapController.handleRequest.mockResolvedValue(accounts); + mockMessenger.handleRequest.mockResolvedValue(accounts); await keyring.handleKeyringSnapMessage(snapId, { method: KeyringEvent.AccountCreated, params: { account: account as unknown as KeyringAccount }, @@ -332,10 +404,7 @@ describe('SnapKeyring', () => { // Reset mock mockCallbacks.addAccount.mockClear(); // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); const params = { account: account as unknown as KeyringAccount, @@ -363,10 +432,7 @@ describe('SnapKeyring', () => { it('creates an account and registers it properly', async () => { // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); const account = ethEoaAccount1; await keyring.handleKeyringSnapMessage(snapId, { @@ -386,10 +452,7 @@ describe('SnapKeyring', () => { it('creates an EOA account and set a default scopes if not provided', async () => { // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); // Omit `scopes` from `account`. const account = noScopes(ethEoaAccount1); @@ -413,10 +476,7 @@ describe('SnapKeyring', () => { it('creating a non-EVM account with the no scope will throw an error', async () => { // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); // Omit `scopes` from non-EVM `account`. const account = noScopes(btcP2wpkhAccount); @@ -436,7 +496,7 @@ describe('SnapKeyring', () => { describe('#handleAccountUpdated', () => { it('updates the methods of an account', async () => { // Return the updated list of accounts when the keyring requests it. - mockSnapController.handleRequest.mockResolvedValue([ + mockMessenger.handleRequest.mockResolvedValue([ { ...ethEoaAccount1, methods: [] }, { ...ethEoaAccount2 }, ]); @@ -574,7 +634,7 @@ describe('SnapKeyring', () => { const account = noScopes(ethEoaAccount1); // Return the updated list of accounts when the keyring requests it. - mockSnapController.handleRequest.mockResolvedValue([{ ...account }]); + mockMessenger.handleRequest.mockResolvedValue([{ ...account }]); expect( await keyring.handleKeyringSnapMessage(snapId, { @@ -593,7 +653,7 @@ describe('SnapKeyring', () => { const account = noScopes(ethErc4337Account); // Return the updated list of accounts when the keyring requests it. - mockSnapController.handleRequest.mockResolvedValue([{ ...account }]); + mockMessenger.handleRequest.mockResolvedValue([{ ...account }]); await expect( keyring.handleKeyringSnapMessage(snapId, { @@ -610,7 +670,7 @@ describe('SnapKeyring', () => { const account = noScopes(btcP2wpkhAccount); // Return the updated list of accounts when the keyring requests it. - mockSnapController.handleRequest.mockResolvedValue([{ ...account }]); + mockMessenger.handleRequest.mockResolvedValue([{ ...account }]); await expect( keyring.handleKeyringSnapMessage(snapId, { @@ -625,7 +685,7 @@ describe('SnapKeyring', () => { describe('#handleAccountDeleted', () => { it('removes an account', async () => { - mockSnapController.handleRequest.mockResolvedValue(null); + mockMessenger.handleRequest.mockResolvedValue(null); mockCallbacks.removeAccount.mockImplementation( async (address, _snapId, handleUserInput) => { await keyring.removeAccount(address); @@ -692,7 +752,7 @@ describe('SnapKeyring', () => { describe('#handleRequestApproved', () => { it('approves an async request', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, }); const requestPromise = keyring.signPersonalMessage( @@ -700,7 +760,7 @@ describe('SnapKeyring', () => { 'hello', ); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId = calls[calls.length - 1][0].request.params.id; await keyring.handleKeyringSnapMessage(snapId, { method: KeyringEvent.RequestApproved, @@ -726,13 +786,13 @@ describe('SnapKeyring', () => { }); it("cannot approve another Snap's request", async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, }); // eslint-disable-next-line no-void void keyring.signPersonalMessage(ethEoaAccount1.address, 'hello'); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId: string = calls[calls.length - 1][0].request.params.id; await expect( keyring.handleKeyringSnapMessage('another-snap-id' as SnapId, { @@ -743,13 +803,13 @@ describe('SnapKeyring', () => { }); it('fails to approve a request that failed when submitted', async () => { - mockSnapController.handleRequest.mockRejectedValue(new Error('error')); + mockMessenger.handleRequest.mockRejectedValue(new Error('error')); const mockMessage = 'Hello World!'; await expect( keyring.signPersonalMessage(ethEoaAccount1.address, mockMessage), ).rejects.toThrow('error'); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId = calls[calls.length - 1][0].request.params.id; const responsePromise = keyring.handleKeyringSnapMessage(snapId, { method: KeyringEvent.RequestApproved, @@ -766,7 +826,7 @@ describe('SnapKeyring', () => { describe('#handleRequestRejected', () => { it('rejects an async request', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, }); const requestPromise = keyring.signPersonalMessage( @@ -774,7 +834,7 @@ describe('SnapKeyring', () => { 'hello', ); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId = calls[calls.length - 1][0].request.params.id; await keyring.handleKeyringSnapMessage(snapId, { method: KeyringEvent.RequestRejected, @@ -798,13 +858,13 @@ describe('SnapKeyring', () => { }); it("cannot reject another Snap's request", async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, }); // eslint-disable-next-line no-void void keyring.signPersonalMessage(ethEoaAccount1.address, 'hello'); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId: string = calls[calls.length - 1][0].request.params.id; await expect( keyring.handleKeyringSnapMessage('another-snap-id' as SnapId, { @@ -871,20 +931,14 @@ describe('SnapKeyring', () => { it('fails to restore an undefined state', async () => { // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); await keyring.deserialize(undefined as unknown as KeyringState); expect(await keyring.getAccounts()).toStrictEqual([]); }); it('fails to restore an empty state', async () => { // Reset the keyring so it's empty. - keyring = new SnapKeyring( - mockSnapController as unknown as SnapController, - mockCallbacks, - ); + keyring = new SnapKeyring(mockSnapKeyringMessenger, mockCallbacks); await expect( keyring.deserialize({} as unknown as KeyringState), ).rejects.toThrow('Cannot convert undefined or null to object'); @@ -949,8 +1003,8 @@ describe('SnapKeyring', () => { }, enabled: true, }; - mockSnapController.get.mockReturnValue(snapObject); - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.get.mockReturnValue(snapObject); + mockMessenger.handleRequest.mockResolvedValue({ pending: true, redirect: { message: 'Go to dapp to continue.', @@ -985,9 +1039,9 @@ describe('SnapKeyring', () => { }, enabled: true, }; - mockSnapController.get.mockReturnValue(snapObject); + mockMessenger.get.mockReturnValue(snapObject); - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, redirect, }); @@ -996,7 +1050,7 @@ describe('SnapKeyring', () => { 'hello', ); - const { calls } = mockSnapController.handleRequest.mock; + const { calls } = mockMessenger.handleRequest.mock; const requestId = calls[calls.length - 1][0].request.params.id; await keyring.handleKeyringSnapMessage(snapId, { method: KeyringEvent.RequestRejected, @@ -1043,9 +1097,9 @@ describe('SnapKeyring', () => { url: 'https://example.com/sign?tx=1234', }; - mockSnapController.get.mockReturnValue(undefined); + mockMessenger.get.mockReturnValue(undefined); - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: true, redirect, }); @@ -1082,7 +1136,7 @@ describe('SnapKeyring', () => { const expectedSignedTx = TransactionFactory.fromTxData(mockSignedTx); const expectedScope = EthScopes.Mainnet; - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: mockSignedTx, }); @@ -1091,7 +1145,7 @@ describe('SnapKeyring', () => { ethEoaAccount1.address, tx, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1163,7 +1217,7 @@ describe('SnapKeyring', () => { '0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c'; it('signs typed data without options', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1172,7 +1226,7 @@ describe('SnapKeyring', () => { ethEoaAccount1.address, dataToSign, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1195,7 +1249,7 @@ describe('SnapKeyring', () => { }); it('signs typed data options (v4)', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1205,7 +1259,7 @@ describe('SnapKeyring', () => { dataToSign, { version: SignTypedDataVersion.V4 }, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1228,7 +1282,7 @@ describe('SnapKeyring', () => { }); it('signs typed data invalid options (v2)', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1238,7 +1292,7 @@ describe('SnapKeyring', () => { dataToSign, { version: 'V2' as any }, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1261,7 +1315,7 @@ describe('SnapKeyring', () => { }); it('signs typed data without domain chainId has no scope', async () => { - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1283,7 +1337,7 @@ describe('SnapKeyring', () => { dataToSignWithoutDomainChainId, { version: SignTypedDataVersion.V4 }, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1335,7 +1389,7 @@ describe('SnapKeyring', () => { bundlerUrl: 'https://bundler.example.com/rpc', }; - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: false, result: expectedBaseUserOp, }); @@ -1346,7 +1400,7 @@ describe('SnapKeyring', () => { executionContext, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1388,7 +1442,7 @@ describe('SnapKeyring', () => { paymasterAndData: '0x1234', }; - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: false, result: expectedPatch, }); @@ -1399,7 +1453,7 @@ describe('SnapKeyring', () => { executionContext, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1437,7 +1491,7 @@ describe('SnapKeyring', () => { signature: '0x', }; - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: false, result: expectedSignature, }); @@ -1448,7 +1502,7 @@ describe('SnapKeyring', () => { executionContext, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ snapId, handler: 'onKeyringRequest', origin: 'metamask', @@ -1476,7 +1530,7 @@ describe('SnapKeyring', () => { it('signs a personal message', async () => { const mockMessage = 'Hello World!'; const expectedSignature = '0x0'; - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1500,7 +1554,7 @@ describe('SnapKeyring', () => { const mockMessage = '0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8'; const expectedSignature = '0x0'; - mockSnapController.handleRequest.mockResolvedValue({ + mockMessenger.handleRequest.mockResolvedValue({ pending: false, result: expectedSignature, }); @@ -1509,7 +1563,7 @@ describe('SnapKeyring', () => { mockMessage, ); expect(signature).toStrictEqual(expectedSignature); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ handler: 'onKeyringRequest', origin: 'metamask', request: { @@ -1547,7 +1601,7 @@ describe('SnapKeyring', () => { }); it('removes an account', async () => { - mockSnapController.handleRequest.mockResolvedValue(null); + mockMessenger.handleRequest.mockResolvedValue(null); await keyring.removeAccount(ethEoaAccount1.address); expect(await keyring.getAccounts()).toStrictEqual([ accounts[1].address, @@ -1560,7 +1614,7 @@ describe('SnapKeyring', () => { it('removes the account and warn if Snap fails', async () => { const spy = jest.spyOn(console, 'error').mockImplementation(); - mockSnapController.handleRequest.mockRejectedValue('some error'); + mockMessenger.handleRequest.mockRejectedValue('some error'); await keyring.removeAccount(ethEoaAccount1.address); expect(await keyring.getAccounts()).toStrictEqual([ accounts[1].address, @@ -1591,7 +1645,7 @@ describe('SnapKeyring', () => { }, enabled: true, }; - mockSnapController.get.mockReturnValue(snapObject); + mockMessenger.get.mockReturnValue(snapObject); const result = keyring.listAccounts(); const expected = accounts.map((a) => ({ ...a, @@ -1624,7 +1678,7 @@ describe('SnapKeyring', () => { id: snapId, enabled: true, }; - mockSnapController.get.mockReturnValue(snapMetadata); + mockMessenger.get.mockReturnValue(snapMetadata); expect(keyring.getAccountByAddress(ethEoaAccount1.address)).toStrictEqual( { ...ethEoaAccount1, @@ -1663,7 +1717,7 @@ describe('SnapKeyring', () => { }; it('calls eth_prepareUserOperation', async () => { - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: false, result: mockExpectedUserOp, }); @@ -1674,7 +1728,7 @@ describe('SnapKeyring', () => { executionContext, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ handler: 'onKeyringRequest', origin: 'metamask', request: { @@ -1696,7 +1750,7 @@ describe('SnapKeyring', () => { }); it('throws error if an pending response is returned from the Snap', async () => { - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: true, }); @@ -1730,7 +1784,7 @@ describe('SnapKeyring', () => { }; it('calls eth_patchUserOperation', async () => { - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: false, result: mockExpectedPatch, }); @@ -1741,7 +1795,7 @@ describe('SnapKeyring', () => { executionContext, ); - expect(mockSnapController.handleRequest).toHaveBeenCalledWith({ + expect(mockMessenger.handleRequest).toHaveBeenCalledWith({ handler: 'onKeyringRequest', origin: 'metamask', request: { @@ -1763,7 +1817,7 @@ describe('SnapKeyring', () => { }); it('throws error if an pending response is returned from the Snap', async () => { - mockSnapController.handleRequest.mockReturnValueOnce({ + mockMessenger.handleRequest.mockReturnValueOnce({ pending: true, }); diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.ts b/packages/keyring-snap-bridge/src/SnapKeyring.ts index 68dd7800..43a2c404 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.ts @@ -25,9 +25,8 @@ import type { EthUserOperationPatch, } from '@metamask/keyring-api'; import type { InternalAccount } from '@metamask/keyring-internal-api'; -import { KeyringSnapControllerClient } from '@metamask/keyring-internal-snap-client'; +import { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client'; import { strictMask } from '@metamask/keyring-utils'; -import type { SnapController } from '@metamask/snaps-controllers'; import type { SnapId } from '@metamask/snaps-sdk'; import { type Snap } from '@metamask/snaps-utils'; import { assert, mask, object, string } from '@metamask/superstruct'; @@ -55,6 +54,7 @@ import { transformAccountV1, } from './migrations'; import { SnapIdMap } from './SnapIdMap'; +import type { SnapKeyringMessenger } from './SnapKeyringMessenger'; import type { SnapMessage } from './types'; import { SnapMessageStruct } from './types'; import { @@ -131,10 +131,15 @@ export class SnapKeyring extends EventEmitter { type: string; + /** + * Messenger to dispatch requests to the Snaps controller. + */ + readonly #messenger: SnapKeyringMessenger; + /** * Client used to call the Snap keyring. */ - readonly #snapClient: KeyringSnapControllerClient; + readonly #snapClient: KeyringInternalSnapClient; /** * Mapping between account IDs and an object that contains the associated @@ -161,14 +166,18 @@ export class SnapKeyring extends EventEmitter { /** * Create a new Snap keyring. * - * @param controller - Snaps controller. + * @param messenger - Snap keyring messenger. * @param callbacks - Callbacks used to interact with other components. * @returns A new Snap keyring. */ - constructor(controller: SnapController, callbacks: SnapKeyringCallbacks) { + constructor( + messenger: SnapKeyringMessenger, + callbacks: SnapKeyringCallbacks, + ) { super(); this.type = SnapKeyring.type; - this.#snapClient = new KeyringSnapControllerClient({ controller }); + this.#messenger = messenger; + this.#snapClient = new KeyringInternalSnapClient({ messenger }); this.#requests = new SnapIdMap(); this.#accounts = new SnapIdMap(); this.#callbacks = callbacks; @@ -658,7 +667,7 @@ export class SnapKeyring extends EventEmitter { */ #validateRedirectUrl(url: string, snapId: SnapId): void { const { origin } = new URL(url); - const snap = this.#snapClient.getController().get(snapId); + const snap = this.#getSnap(snapId); if (!snap) { throw new Error(`Snap '${snapId}' not found.`); } @@ -934,6 +943,16 @@ export class SnapKeyring extends EventEmitter { ); } + /** + * Get the Snap associated with the given Snap ID. + * + * @param snapId - Snap ID. + * @returns The Snap or undefined if the Snap cannot be found. + */ + #getSnap(snapId: SnapId): Snap | undefined { + return this.#messenger.call('SnapController:get', snapId); + } + /** * Get the metadata of a Snap keyring account. * @@ -943,7 +962,7 @@ export class SnapKeyring extends EventEmitter { #getSnapMetadata( snapId: SnapId, ): InternalAccount['metadata']['snap'] | undefined { - const snap = this.#snapClient.getController().get(snapId); + const snap = this.#getSnap(snapId); return snap ? { id: snapId, name: snap.manifest.proposedName, enabled: snap.enabled } : undefined; diff --git a/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts b/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts new file mode 100644 index 00000000..9932b367 --- /dev/null +++ b/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts @@ -0,0 +1,14 @@ +import type { RestrictedControllerMessenger } from '@metamask/base-controller'; +import type { HandleSnapRequest, GetSnap } from '@metamask/snaps-controllers'; + +export type SnapKeyringAllowedActions = HandleSnapRequest | GetSnap; + +export type SnapKeyringAllowedEvents = never; + +export type SnapKeyringMessenger = RestrictedControllerMessenger< + 'SnapKeyringMessenger', + SnapKeyringAllowedActions, + SnapKeyringAllowedEvents, + SnapKeyringAllowedActions['type'], + SnapKeyringAllowedEvents['type'] +>; diff --git a/yarn.lock b/yarn.lock index cdbd90d7..2aa8ef9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1739,13 +1739,13 @@ __metadata: languageName: node linkType: hard -"@metamask/base-controller@npm:^7.0.0": - version: 7.0.0 - resolution: "@metamask/base-controller@npm:7.0.0" +"@metamask/base-controller@npm:^7.0.0, @metamask/base-controller@npm:^7.1.1": + version: 7.1.1 + resolution: "@metamask/base-controller@npm:7.1.1" dependencies: - "@metamask/utils": "npm:^9.1.0" + "@metamask/utils": "npm:^11.0.1" immer: "npm:^9.0.6" - checksum: 10/0ea307da4a7863224fd1fc83039165dbd06d2725922d4d4cf5854f5e7894e789a3c277f1e4592a38ae002de869217a26550f3b9687c259fc29153984dc5b4a4c + checksum: 10/d45abc9e0f3f42a0ea7f0a52734f3749fafc5fefc73608230ab0815578e83a9fc28fe57dc7000f6f8df2cdcee5b53f68bb971091075bec9de6b7f747de627c60 languageName: node linkType: hard @@ -1997,12 +1997,12 @@ __metadata: "@lavamoat/allow-scripts": "npm:^3.2.1" "@lavamoat/preinstall-always-fail": "npm:^2.1.0" "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/base-controller": "npm:^7.1.1" "@metamask/eth-sig-util": "npm:^8.1.2" "@metamask/keyring-api": "workspace:^" "@metamask/keyring-internal-api": "workspace:^" "@metamask/keyring-internal-snap-client": "workspace:^" "@metamask/keyring-utils": "workspace:^" - "@metamask/providers": "npm:^18.3.1" "@metamask/snaps-controllers": "npm:^9.10.0" "@metamask/snaps-sdk": "npm:^6.7.0" "@metamask/snaps-utils": "npm:^8.3.0" @@ -2022,10 +2022,8 @@ __metadata: typedoc: "npm:^0.25.13" typescript: "npm:~5.6.3" uuid: "npm:^9.0.1" - webextension-polyfill: "npm:^0.12.0" peerDependencies: "@metamask/keyring-api": "workspace:^" - "@metamask/providers": ^18.3.1 languageName: unknown linkType: soft @@ -2198,10 +2196,10 @@ __metadata: "@lavamoat/allow-scripts": "npm:^3.2.1" "@lavamoat/preinstall-always-fail": "npm:^2.1.0" "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/base-controller": "npm:^7.1.1" "@metamask/keyring-api": "workspace:^" "@metamask/keyring-snap-client": "workspace:^" "@metamask/keyring-utils": "workspace:^" - "@metamask/providers": "npm:^18.3.1" "@metamask/snaps-controllers": "npm:^9.10.0" "@metamask/snaps-sdk": "npm:^6.7.0" "@metamask/snaps-utils": "npm:^8.3.0" @@ -2219,9 +2217,6 @@ __metadata: tsd: "npm:^0.31.0" typedoc: "npm:^0.25.13" typescript: "npm:~5.6.3" - webextension-polyfill: "npm:^0.12.0" - peerDependencies: - "@metamask/providers": ^18.3.1 languageName: unknown linkType: soft From 9268444652638187fac8bcd8ad93b0203087c404 Mon Sep 17 00:00:00 2001 From: Xiaoming Wang <7315988+dawnseeker8@users.noreply.github.com> Date: Thu, 23 Jan 2025 17:31:48 +0800 Subject: [PATCH 3/8] fix(keyring-eth-ledger-bridge): bump `@ledgerhq/hw-app-eth` to `^6.42.0` to fix Ledger's handling of EIP-712 (#153) Upgrade `@ledgerhq/hw-app-eth` to `6.42.0`. This will fix Ledger's handling of EIP-712 content. --- .../keyring-eth-ledger-bridge/package.json | 2 +- yarn.lock | 353 +++--------------- 2 files changed, 58 insertions(+), 297 deletions(-) diff --git a/packages/keyring-eth-ledger-bridge/package.json b/packages/keyring-eth-ledger-bridge/package.json index 91f49447..61bbc4c8 100644 --- a/packages/keyring-eth-ledger-bridge/package.json +++ b/packages/keyring-eth-ledger-bridge/package.json @@ -50,7 +50,7 @@ "@ethereumjs/rlp": "^5.0.2", "@ethereumjs/tx": "^4.2.0", "@ethereumjs/util": "^8.1.0", - "@ledgerhq/hw-app-eth": "^6.39.0", + "@ledgerhq/hw-app-eth": "^6.42.0", "@metamask/eth-sig-util": "^8.1.2", "hdkey": "^2.1.0" }, diff --git a/yarn.lock b/yarn.lock index 2aa8ef9b..db1fdccb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -676,7 +676,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.7.0": +"@ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" dependencies: @@ -693,7 +693,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:5.7.0, @ethersproject/abstract-provider@npm:^5.7.0": +"@ethersproject/abstract-provider@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-provider@npm:5.7.0" dependencies: @@ -708,7 +708,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:5.7.0, @ethersproject/abstract-signer@npm:^5.7.0": +"@ethersproject/abstract-signer@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-signer@npm:5.7.0" dependencies: @@ -721,7 +721,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:5.7.0, @ethersproject/address@npm:^5.7.0": +"@ethersproject/address@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/address@npm:5.7.0" dependencies: @@ -734,7 +734,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/base64@npm:5.7.0, @ethersproject/base64@npm:^5.7.0": +"@ethersproject/base64@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/base64@npm:5.7.0" dependencies: @@ -743,17 +743,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/basex@npm:5.7.0, @ethersproject/basex@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/basex@npm:5.7.0" - dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - checksum: 10/840e333e109bff2fcf8d91dcfd45fa951835844ef0e1ba710037e87291c7b5f3c189ba86f6cee2ca7de2ede5b7d59fbb930346607695855bee20d2f9f63371ef - languageName: node - linkType: hard - -"@ethersproject/bignumber@npm:5.7.0, @ethersproject/bignumber@npm:^5.7.0": +"@ethersproject/bignumber@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bignumber@npm:5.7.0" dependencies: @@ -764,7 +754,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:5.7.0, @ethersproject/bytes@npm:^5.7.0": +"@ethersproject/bytes@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bytes@npm:5.7.0" dependencies: @@ -773,7 +763,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:5.7.0, @ethersproject/constants@npm:^5.7.0": +"@ethersproject/constants@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/constants@npm:5.7.0" dependencies: @@ -782,25 +772,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/contracts@npm:5.7.0": - version: 5.7.0 - resolution: "@ethersproject/contracts@npm:5.7.0" - dependencies: - "@ethersproject/abi": "npm:^5.7.0" - "@ethersproject/abstract-provider": "npm:^5.7.0" - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - checksum: 10/5df66179af242faabea287a83fd2f8f303a4244dc87a6ff802e1e3b643f091451295c8e3d088c7739970b7915a16a581c192d4e007d848f1fdf3cc9e49010053 - languageName: node - linkType: hard - -"@ethersproject/hash@npm:5.7.0, @ethersproject/hash@npm:^5.7.0": +"@ethersproject/hash@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/hash@npm:5.7.0" dependencies: @@ -817,48 +789,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hdnode@npm:5.7.0, @ethersproject/hdnode@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/hdnode@npm:5.7.0" - dependencies: - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/basex": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/pbkdf2": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/sha2": "npm:^5.7.0" - "@ethersproject/signing-key": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - "@ethersproject/wordlists": "npm:^5.7.0" - checksum: 10/2fbe6278c324235afaa88baa5dea24d8674c72b14ad037fe2096134d41025977f410b04fd146e333a1b6cac9482e9de62d6375d1705fd42667543f2d0eb66655 - languageName: node - linkType: hard - -"@ethersproject/json-wallets@npm:5.7.0, @ethersproject/json-wallets@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/json-wallets@npm:5.7.0" - dependencies: - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/hdnode": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/pbkdf2": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/random": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - aes-js: "npm:3.0.0" - scrypt-js: "npm:3.0.1" - checksum: 10/4a1ef0912ffc8d18c392ae4e292948d86bffd715fe3dd3e66d1cd21f6c9267aeadad4da84261db853327f97cdfd765a377f9a87e39d4c6749223a69226faf0a1 - languageName: node - linkType: hard - -"@ethersproject/keccak256@npm:5.7.0, @ethersproject/keccak256@npm:^5.7.0": +"@ethersproject/keccak256@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/keccak256@npm:5.7.0" dependencies: @@ -868,14 +799,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:5.7.0, @ethersproject/logger@npm:^5.7.0": +"@ethersproject/logger@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/logger@npm:5.7.0" checksum: 10/683a939f467ae7510deedc23d7611d0932c3046137f5ffb92ba1e3c8cd9cf2fbbaa676b660c248441a0fa9143783137c46d6e6d17d676188dd5a6ef0b72dd091 languageName: node linkType: hard -"@ethersproject/networks@npm:5.7.1, @ethersproject/networks@npm:^5.7.0": +"@ethersproject/networks@npm:^5.7.0": version: 5.7.1 resolution: "@ethersproject/networks@npm:5.7.1" dependencies: @@ -884,17 +815,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/pbkdf2@npm:5.7.0, @ethersproject/pbkdf2@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/pbkdf2@npm:5.7.0" - dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/sha2": "npm:^5.7.0" - checksum: 10/dea7ba747805e24b81dfb99e695eb329509bf5cad1a42e48475ade28e060e567458a3d5bf930f302691bded733fd3fa364f0c7adce920f9f05a5ef8c13267aaa - languageName: node - linkType: hard - -"@ethersproject/properties@npm:5.7.0, @ethersproject/properties@npm:^5.7.0": +"@ethersproject/properties@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/properties@npm:5.7.0" dependencies: @@ -903,45 +824,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:5.7.2": - version: 5.7.2 - resolution: "@ethersproject/providers@npm:5.7.2" - dependencies: - "@ethersproject/abstract-provider": "npm:^5.7.0" - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/base64": "npm:^5.7.0" - "@ethersproject/basex": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/hash": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/networks": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/random": "npm:^5.7.0" - "@ethersproject/rlp": "npm:^5.7.0" - "@ethersproject/sha2": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - "@ethersproject/web": "npm:^5.7.0" - bech32: "npm:1.1.4" - ws: "npm:7.4.6" - checksum: 10/8534a1896e61b9f0b66427a639df64a5fe76d0c08ec59b9f0cc64fdd1d0cc28d9fc3312838ae8d7817c8f5e2e76b7f228b689bc33d1cbb8e1b9517d4c4f678d8 - languageName: node - linkType: hard - -"@ethersproject/random@npm:5.7.0, @ethersproject/random@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/random@npm:5.7.0" - dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/c23ec447998ce1147651bd58816db4d12dbeb404f66a03d14a13e1edb439879bab18528e1fc46b931502903ac7b1c08ea61d6a86e621a6e060fa63d41aeed3ac - languageName: node - linkType: hard - -"@ethersproject/rlp@npm:5.7.0, @ethersproject/rlp@npm:^5.5.0, @ethersproject/rlp@npm:^5.7.0": +"@ethersproject/rlp@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/rlp@npm:5.7.0" dependencies: @@ -951,18 +834,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/sha2@npm:5.7.0, @ethersproject/sha2@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/sha2@npm:5.7.0" - dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - hash.js: "npm:1.1.7" - checksum: 10/09321057c022effbff4cc2d9b9558228690b5dd916329d75c4b1ffe32ba3d24b480a367a7cc92d0f0c0b1c896814d03351ae4630e2f1f7160be2bcfbde435dbc - languageName: node - linkType: hard - -"@ethersproject/signing-key@npm:5.7.0, @ethersproject/signing-key@npm:^5.7.0": +"@ethersproject/signing-key@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/signing-key@npm:5.7.0" dependencies: @@ -976,21 +848,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/solidity@npm:5.7.0": - version: 5.7.0 - resolution: "@ethersproject/solidity@npm:5.7.0" - dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/sha2": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - checksum: 10/9a02f37f801c96068c3e7721f83719d060175bc4e80439fe060e92bd7acfcb6ac1330c7e71c49f4c2535ca1308f2acdcb01e00133129aac00581724c2d6293f3 - languageName: node - linkType: hard - -"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:^5.7.0": +"@ethersproject/strings@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/strings@npm:5.7.0" dependencies: @@ -1001,7 +859,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:5.7.0, @ethersproject/transactions@npm:^5.7.0": +"@ethersproject/transactions@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/transactions@npm:5.7.0" dependencies: @@ -1018,41 +876,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:5.7.0": - version: 5.7.0 - resolution: "@ethersproject/units@npm:5.7.0" - dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/304714f848cd32e57df31bf545f7ad35c2a72adae957198b28cbc62166daa929322a07bff6e9c9ac4577ab6aa0de0546b065ed1b2d20b19e25748b7d475cb0fc - languageName: node - linkType: hard - -"@ethersproject/wallet@npm:5.7.0": - version: 5.7.0 - resolution: "@ethersproject/wallet@npm:5.7.0" - dependencies: - "@ethersproject/abstract-provider": "npm:^5.7.0" - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/hash": "npm:^5.7.0" - "@ethersproject/hdnode": "npm:^5.7.0" - "@ethersproject/json-wallets": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/random": "npm:^5.7.0" - "@ethersproject/signing-key": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - "@ethersproject/wordlists": "npm:^5.7.0" - checksum: 10/340f8e5c77c6c47c4d1596c200d97c53c1d4b4eb54d9166d0f2a114cb81685e7689255b0627e917fbcdc29cb54c4bd1f1a9909f3096ef9dff9acc0b24972f1c1 - languageName: node - linkType: hard - -"@ethersproject/web@npm:5.7.1, @ethersproject/web@npm:^5.7.0": +"@ethersproject/web@npm:^5.7.0": version: 5.7.1 resolution: "@ethersproject/web@npm:5.7.1" dependencies: @@ -1065,19 +889,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wordlists@npm:5.7.0, @ethersproject/wordlists@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/wordlists@npm:5.7.0" - dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/hash": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - checksum: 10/737fca67ad743a32020f50f5b9e147e5683cfba2692367c1124a5a5538be78515865257b426ec9141daac91a70295e5e21bef7a193b79fe745f1be378562ccaa - languageName: node - linkType: hard - "@fivebinaries/coin-selection@npm:2.2.1": version: 2.2.1 resolution: "@fivebinaries/coin-selection@npm:2.2.1" @@ -1484,13 +1295,13 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/cryptoassets-evm-signatures@npm:^13.5.0": - version: 13.5.0 - resolution: "@ledgerhq/cryptoassets-evm-signatures@npm:13.5.0" +"@ledgerhq/cryptoassets-evm-signatures@npm:^13.5.2": + version: 13.5.2 + resolution: "@ledgerhq/cryptoassets-evm-signatures@npm:13.5.2" dependencies: - "@ledgerhq/live-env": "npm:^2.3.0" + "@ledgerhq/live-env": "npm:^2.4.1" axios: "npm:1.7.7" - checksum: 10/ce6e3343fdf60255ede1d784a2fb47c8c5f49e8257559947e2678fac250700140695c85ae06bef777ccc4bb37577db813a4b3d031f3b0b84cbcd6e139613fbf9 + checksum: 10/2cf692c111523fa634a6eeadfbe1e9eca29fd9e8c03a04dac00f0c191becdc0300bf90d1a5a0190b6ac8cf1436bb14009b50039e3611c55dd6843a6ec45230ec languageName: node linkType: hard @@ -1506,18 +1317,18 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/domain-service@npm:^1.2.6": - version: 1.2.6 - resolution: "@ledgerhq/domain-service@npm:1.2.6" +"@ledgerhq/domain-service@npm:^1.2.15": + version: 1.2.15 + resolution: "@ledgerhq/domain-service@npm:1.2.15" dependencies: "@ledgerhq/errors": "npm:^6.19.1" "@ledgerhq/logs": "npm:^6.12.0" - "@ledgerhq/types-live": "npm:^6.52.0" + "@ledgerhq/types-live": "npm:^6.56.0" axios: "npm:1.7.7" eip55: "npm:^2.1.1" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" - checksum: 10/0b680af9deff24f608446cb7026b06e09ea693a367a5ef5e71068c70fabfbb98019cb618daefed278ed875a0ff5d296735fb743746ac0edee1357ae12fd58d99 + checksum: 10/04585a2558512fa0bf07df89d608449cb184c3ae61d33364e67701b42353bd28c922c2bd5e8b6f843beffa3ae5667f3bc7bc9802a5c6a977ddf75a15f10e3895 languageName: node linkType: hard @@ -1528,37 +1339,39 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/evm-tools@npm:^1.2.3": - version: 1.2.3 - resolution: "@ledgerhq/evm-tools@npm:1.2.3" +"@ledgerhq/evm-tools@npm:^1.3.0": + version: 1.3.0 + resolution: "@ledgerhq/evm-tools@npm:1.3.0" dependencies: - "@ledgerhq/cryptoassets-evm-signatures": "npm:^13.5.0" - "@ledgerhq/live-env": "npm:^2.3.0" + "@ethersproject/constants": "npm:^5.7.0" + "@ethersproject/hash": "npm:^5.7.0" + "@ledgerhq/cryptoassets-evm-signatures": "npm:^13.5.2" + "@ledgerhq/live-env": "npm:^2.4.1" axios: "npm:1.7.7" crypto-js: "npm:4.2.0" - ethers: "npm:5.7.2" - checksum: 10/956a0a3ac26454ac350c5e34b5cfb911ed3a0f3f724bec1ce2c56f2de344635b582f977e4901841c353d98c50b076e40bfb03d865eed3a82e328744043e00ee7 + checksum: 10/e4394a3065391d44efe958a043df6fade68e789f18386d2a22f51574eb6b723151c8e631af2bce21b951b1908930145181cf8db41fe546e4a06c34a81cb3ff6b languageName: node linkType: hard -"@ledgerhq/hw-app-eth@npm:^6.39.0": - version: 6.39.0 - resolution: "@ledgerhq/hw-app-eth@npm:6.39.0" +"@ledgerhq/hw-app-eth@npm:^6.42.0": + version: 6.42.2 + resolution: "@ledgerhq/hw-app-eth@npm:6.42.2" dependencies: - "@ethersproject/abi": "npm:^5.5.0" - "@ethersproject/rlp": "npm:^5.5.0" - "@ledgerhq/cryptoassets-evm-signatures": "npm:^13.5.0" - "@ledgerhq/domain-service": "npm:^1.2.6" + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/rlp": "npm:^5.7.0" + "@ethersproject/transactions": "npm:^5.7.0" + "@ledgerhq/cryptoassets-evm-signatures": "npm:^13.5.2" + "@ledgerhq/domain-service": "npm:^1.2.15" "@ledgerhq/errors": "npm:^6.19.1" - "@ledgerhq/evm-tools": "npm:^1.2.3" + "@ledgerhq/evm-tools": "npm:^1.3.0" "@ledgerhq/hw-transport": "npm:^6.31.4" "@ledgerhq/hw-transport-mocker": "npm:^6.29.4" "@ledgerhq/logs": "npm:^6.12.0" - "@ledgerhq/types-live": "npm:^6.52.0" + "@ledgerhq/types-live": "npm:^6.56.0" axios: "npm:1.7.7" bignumber.js: "npm:^9.1.2" semver: "npm:^7.3.5" - checksum: 10/5b50aac35989e09704557523efe5b6b29a1f31f5279088ecceb90164e32e05860f3ff20c32a084003a69723ed08165ae140c2987424657245f088c3f9a908cd6 + checksum: 10/58a80daa4a1d6881fc0188ee68f6d3ff76c753e558e9b299cc0ae04859a111881c372445c06bc7c68f25b03aa51a31c335cc3fc4188c25552fc490c7da85fcdc languageName: node linkType: hard @@ -1585,13 +1398,13 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/live-env@npm:^2.3.0": - version: 2.3.0 - resolution: "@ledgerhq/live-env@npm:2.3.0" +"@ledgerhq/live-env@npm:^2.4.1": + version: 2.4.1 + resolution: "@ledgerhq/live-env@npm:2.4.1" dependencies: rxjs: "npm:^7.8.1" utility-types: "npm:^3.10.0" - checksum: 10/757ff834d6b94dce0487d60ab0efa45ef206ebbdfd29053c232b4c0fdce1594016531340c1603695b37f17deb1639dcb98078a9629eeb36c835a19f4180834ce + checksum: 10/e8f5f13d77619f0e2b83907fa2a4e80f9e1ed18aeba0cfb2dcafe4d505ed4dd811a1b508ca752a4fd3782f8e5cf651a9daea0cb17d57e9159f915042b94b867d languageName: node linkType: hard @@ -1616,13 +1429,13 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/types-live@npm:^6.52.0": - version: 6.52.0 - resolution: "@ledgerhq/types-live@npm:6.52.0" +"@ledgerhq/types-live@npm:^6.52.0, @ledgerhq/types-live@npm:^6.56.0": + version: 6.56.0 + resolution: "@ledgerhq/types-live@npm:6.56.0" dependencies: bignumber.js: "npm:^9.1.2" rxjs: "npm:^7.8.1" - checksum: 10/c410f02159538d66f59956512fc5bab2cb17edee7f6a15a517c31d89d6c730e52691666bb2e1d98718c701e94306dd7498544ea3d7772ff0b5ad6522fb2c335c + checksum: 10/a3cdf2acc6b4fa41aa34993f8790d44aa4fa937378b0bce29a69889b43e5229662803530b948206fe9fe02498d25058e71db2b14f22dc53445df7f53e547c308 languageName: node linkType: hard @@ -1896,7 +1709,7 @@ __metadata: "@ethereumjs/util": "npm:^8.1.0" "@lavamoat/allow-scripts": "npm:^3.2.1" "@lavamoat/preinstall-always-fail": "npm:^2.1.0" - "@ledgerhq/hw-app-eth": "npm:^6.39.0" + "@ledgerhq/hw-app-eth": "npm:^6.42.0" "@ledgerhq/hw-transport": "npm:^6.31.3" "@ledgerhq/types-cryptoassets": "npm:^7.15.1" "@ledgerhq/types-devices": "npm:^6.25.3" @@ -4112,13 +3925,6 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:3.0.0": - version: 3.0.0 - resolution: "aes-js@npm:3.0.0" - checksum: 10/1b3772e5ba74abdccb6c6b99bf7f50b49057b38c0db1612b46c7024414f16e65ba7f1643b2d6e38490b1870bdf3ba1b87b35e2c831fd3fdaeff015f08aad19d1 - languageName: node - linkType: hard - "aes-js@npm:^3.1.2": version: 3.1.2 resolution: "aes-js@npm:3.1.2" @@ -4523,13 +4329,6 @@ __metadata: languageName: node linkType: hard -"bech32@npm:1.1.4": - version: 1.1.4 - resolution: "bech32@npm:1.1.4" - checksum: 10/63ff37c0ce43be914c685ce89700bba1589c319af0dac1ea04f51b33d0e5ecfd40d14c24f527350b94f0a4e236385373bb9122ec276410f354ddcdbf29ca13f4 - languageName: node - linkType: hard - "bech32@npm:^2.0.0": version: 2.0.0 resolution: "bech32@npm:2.0.0" @@ -6353,44 +6152,6 @@ __metadata: languageName: node linkType: hard -"ethers@npm:5.7.2": - version: 5.7.2 - resolution: "ethers@npm:5.7.2" - dependencies: - "@ethersproject/abi": "npm:5.7.0" - "@ethersproject/abstract-provider": "npm:5.7.0" - "@ethersproject/abstract-signer": "npm:5.7.0" - "@ethersproject/address": "npm:5.7.0" - "@ethersproject/base64": "npm:5.7.0" - "@ethersproject/basex": "npm:5.7.0" - "@ethersproject/bignumber": "npm:5.7.0" - "@ethersproject/bytes": "npm:5.7.0" - "@ethersproject/constants": "npm:5.7.0" - "@ethersproject/contracts": "npm:5.7.0" - "@ethersproject/hash": "npm:5.7.0" - "@ethersproject/hdnode": "npm:5.7.0" - "@ethersproject/json-wallets": "npm:5.7.0" - "@ethersproject/keccak256": "npm:5.7.0" - "@ethersproject/logger": "npm:5.7.0" - "@ethersproject/networks": "npm:5.7.1" - "@ethersproject/pbkdf2": "npm:5.7.0" - "@ethersproject/properties": "npm:5.7.0" - "@ethersproject/providers": "npm:5.7.2" - "@ethersproject/random": "npm:5.7.0" - "@ethersproject/rlp": "npm:5.7.0" - "@ethersproject/sha2": "npm:5.7.0" - "@ethersproject/signing-key": "npm:5.7.0" - "@ethersproject/solidity": "npm:5.7.0" - "@ethersproject/strings": "npm:5.7.0" - "@ethersproject/transactions": "npm:5.7.0" - "@ethersproject/units": "npm:5.7.0" - "@ethersproject/wallet": "npm:5.7.0" - "@ethersproject/web": "npm:5.7.1" - "@ethersproject/wordlists": "npm:5.7.0" - checksum: 10/227dfa88a2547c799c0c3c9e92e5e246dd11342f4b495198b3ae7c942d5bf81d3970fcef3fbac974a9125d62939b2d94f3c0458464e702209b839a8e6e615028 - languageName: node - linkType: hard - "ethjs-util@npm:0.1.6, ethjs-util@npm:^0.1.3, ethjs-util@npm:^0.1.6": version: 0.1.6 resolution: "ethjs-util@npm:0.1.6" @@ -10386,7 +10147,7 @@ __metadata: languageName: node linkType: hard -"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": +"scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" checksum: 10/2f8aa72b7f76a6f9c446bbec5670f80d47497bccce98474203d89b5667717223eeb04a50492ae685ed7adc5a060fc2d8f9fd988f8f7ebdaf3341967f3aeff116 From bc7161bf4aec8f676cd5a1d45ebe09927ec8ecb1 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Thu, 23 Jan 2025 11:18:29 +0100 Subject: [PATCH 4/8] release: 22.0.0 (#158) # Description This is the release candidate for version 22.0.0. See the CHANGELOGs for more details. --- package.json | 2 +- packages/keyring-eth-ledger-bridge/CHANGELOG.md | 10 +++++++++- packages/keyring-eth-ledger-bridge/package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 51204e8f..191b3806 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/accounts-monorepo", - "version": "21.0.0", + "version": "22.0.0", "private": true, "description": "Monorepo for MetaMask accounts related packages", "repository": { diff --git a/packages/keyring-eth-ledger-bridge/CHANGELOG.md b/packages/keyring-eth-ledger-bridge/CHANGELOG.md index cb61b85e..2f3691fb 100644 --- a/packages/keyring-eth-ledger-bridge/CHANGELOG.md +++ b/packages/keyring-eth-ledger-bridge/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [8.0.3] + +### Fixed + +- Bump `@ledgerhq/hw-app-eth` dependency from `^6.39.0` to `^6.42.0` ([#153](https://github.com/MetaMask/accounts/pull/153)) + - Required to fix handling of EIP-712 content. + ## [8.0.2] ### Changed @@ -240,7 +247,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support new versions of ethereumjs/tx ([#68](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/68)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@8.0.2...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@8.0.3...HEAD +[8.0.3]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@8.0.2...@metamask/eth-ledger-bridge-keyring@8.0.3 [8.0.2]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@8.0.1...@metamask/eth-ledger-bridge-keyring@8.0.2 [8.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@8.0.0...@metamask/eth-ledger-bridge-keyring@8.0.1 [8.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@7.0.0...@metamask/eth-ledger-bridge-keyring@8.0.0 diff --git a/packages/keyring-eth-ledger-bridge/package.json b/packages/keyring-eth-ledger-bridge/package.json index 61bbc4c8..94b5ec5a 100644 --- a/packages/keyring-eth-ledger-bridge/package.json +++ b/packages/keyring-eth-ledger-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/eth-ledger-bridge-keyring", - "version": "8.0.2", + "version": "8.0.3", "description": "A MetaMask compatible keyring, for ledger hardware wallets", "keywords": [ "ethereum", From 7fe6e0bebed9d9fe7797b7a21e9b9b4d7a991660 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Thu, 23 Jan 2025 18:30:22 +0100 Subject: [PATCH 5/8] feat: add `account{AssetList,Balances,Transactions}Updated` keyring events + re-publish (#154) Now that the `SnapKeyring` uses a `Messenger` to interact with some controllers (`SnapController` only for now). We can re-use this messenger to forward new events coming out from the Snap. Those events will be mainly consumed by the new `Multichain*Controller`(s). This allows to use a "pub/sub pattern" rather than relying on polling information out from the Snap. All those information can still be fetched explicitly from the Snap: - `accountBalancesUpdated` -> `Keyring.getAccountBalances` - `accountTransactionsUpdated` -> `Keyring.listAccountTransactions` - `accountAssetListUpdated` -> `OnAssetLookup` (through [SIP-29](https://github.com/MetaMask/SIPs/pull/154), once available) --- packages/keyring-api/src/api/account.ts | 4 +- packages/keyring-api/src/api/asset.ts | 25 ++- packages/keyring-api/src/events.ts | 147 ++++++++++++++++- .../src/SnapKeyring.test.ts | 156 ++++++++++++------ .../keyring-snap-bridge/src/SnapKeyring.ts | 81 ++++++++- .../src/SnapKeyringMessenger.ts | 38 ++++- packages/keyring-snap-bridge/src/index.ts | 1 + packages/keyring-utils/src/types.ts | 4 + 8 files changed, 388 insertions(+), 68 deletions(-) diff --git a/packages/keyring-api/src/api/account.ts b/packages/keyring-api/src/api/account.ts index 647909a2..f0cc4661 100644 --- a/packages/keyring-api/src/api/account.ts +++ b/packages/keyring-api/src/api/account.ts @@ -1,4 +1,4 @@ -import { object, UuidStruct } from '@metamask/keyring-utils'; +import { AccountIdStruct, object } from '@metamask/keyring-utils'; import type { Infer } from '@metamask/superstruct'; import { nonempty, @@ -56,7 +56,7 @@ export const KeyringAccountStruct = object({ /** * Account ID (UUIDv4). */ - id: UuidStruct, + id: AccountIdStruct, /** * Account type. diff --git a/packages/keyring-api/src/api/asset.ts b/packages/keyring-api/src/api/asset.ts index f46623a7..154a3390 100644 --- a/packages/keyring-api/src/api/asset.ts +++ b/packages/keyring-api/src/api/asset.ts @@ -11,6 +11,21 @@ import { isPlainObject, } from '@metamask/utils'; +/** + * Fungible asset amount struct. + */ +export const FungibleAssetAmountStruct = object({ + /** + * Asset unit. + */ + unit: string(), + + /** + * Asset amount. + */ + amount: StringNumberStruct, +}); + /** * Fungible asset struct. */ @@ -25,15 +40,7 @@ export const FungibleAssetStruct = object({ */ type: CaipAssetTypeStruct, - /** - * Asset unit. - */ - unit: string(), - - /** - * Asset amount. - */ - amount: StringNumberStruct, + ...FungibleAssetAmountStruct.schema, }); /** diff --git a/packages/keyring-api/src/events.ts b/packages/keyring-api/src/events.ts index b5e433f6..c3c95295 100644 --- a/packages/keyring-api/src/events.ts +++ b/packages/keyring-api/src/events.ts @@ -1,8 +1,19 @@ -import { exactOptional, object, UuidStruct } from '@metamask/keyring-utils'; -import { boolean, literal, string } from '@metamask/superstruct'; -import { JsonStruct } from '@metamask/utils'; +import { + exactOptional, + object, + UuidStruct, + AccountIdStruct, +} from '@metamask/keyring-utils'; +import type { Infer } from '@metamask/superstruct'; +import { array, boolean, literal, record, string } from '@metamask/superstruct'; +import { CaipAssetTypeStruct, JsonStruct } from '@metamask/utils'; -import { KeyringAccountStruct } from './api'; +import { + CaipAssetTypeOrIdStruct, + FungibleAssetAmountStruct, + KeyringAccountStruct, + TransactionStruct, +} from './api'; /** * Supported keyring events. @@ -16,6 +27,11 @@ export enum KeyringEvent { // Request events RequestApproved = 'notify:requestApproved', RequestRejected = 'notify:requestRejected', + + // Assets related events + AccountBalancesUpdated = 'notify:accountBalancesUpdated', + AccountAssetListUpdated = 'notify:accountAssetListUpdated', + AccountTransactionsUpdated = 'notify:accountTransactionsUpdated', } export const AccountCreatedEventStruct = object({ @@ -87,3 +103,126 @@ export const RequestRejectedEventStruct = object({ id: UuidStruct, }), }); + +// Assets related events: +// ----------------------------------------------------------------------------------------------- + +export const AccountBalancesUpdatedEventStruct = object({ + method: literal(`${KeyringEvent.AccountBalancesUpdated}`), + params: object({ + /** + * Balances updates of accounts owned by the Snap. + */ + balances: record( + /** + * Account ID. + */ + AccountIdStruct, + + /** + * Mapping of each owned assets and their respective balances for that account. + */ + record( + /** + * Asset type (CAIP-19). + */ + CaipAssetTypeStruct, + + /** + * Balance information for a given asset. + */ + FungibleAssetAmountStruct, + ), + ), + }), +}); + +/** + * Event emitted when the balances of an account are updated. + * + * Only changes are reported. + * + * The Snap can choose to emit this event for multiple accounts at once. + */ +export type AccountBalancesUpdatedEvent = Infer< + typeof AccountBalancesUpdatedEventStruct +>; +export type AccountBalancesUpdatedEventPayload = + AccountBalancesUpdatedEvent['params']; + +export const AccountTransactionsUpdatedEventStruct = object({ + method: literal(`${KeyringEvent.AccountTransactionsUpdated}`), + params: object({ + /** + * Transactions updates of accounts owned by the Snap. + */ + transactions: record( + /** + * Account ID. + */ + AccountIdStruct, + + /** + * List of updated transactions for that account. + */ + array(TransactionStruct), + ), + }), +}); + +/** + * Event emitted when the transactions of an account are updated (added or + * changed). + * + * Only changes are reported. + * + * The Snap can choose to emit this event for multiple accounts at once. + */ +export type AccountTransactionsUpdatedEvent = Infer< + typeof AccountTransactionsUpdatedEventStruct +>; +export type AccountTransactionsUpdatedEventPayload = + AccountTransactionsUpdatedEvent['params']; + +export const AccountAssetListUpdatedEventStruct = object({ + method: literal(`${KeyringEvent.AccountAssetListUpdated}`), + params: object({ + /** + * Asset list update of accounts owned by the Snap. + */ + assets: record( + /** + * Account ID. + */ + AccountIdStruct, + + /** + * Asset list changes for that account. + */ + object({ + /** + * New assets detected. + */ + added: array(CaipAssetTypeOrIdStruct), + + /** + * Assets no longer available on that account. + */ + removed: array(CaipAssetTypeOrIdStruct), + }), + ), + }), +}); + +/** + * Event emitted when the assets of an account are updated. + * + * Only changes are reported. + * + * The Snap can choose to emit this event for multiple accounts at once. + */ +export type AccountAssetListUpdatedEvent = Infer< + typeof AccountAssetListUpdatedEventStruct +>; +export type AccountAssetListUpdatedEventPayload = + AccountAssetListUpdatedEvent['params']; diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts index f53e3499..1c61145d 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts @@ -7,6 +7,9 @@ import type { EthBaseUserOperation, EthUserOperation, EthUserOperationPatch, + AccountBalancesUpdatedEventPayload, + AccountTransactionsUpdatedEventPayload, + AccountAssetListUpdatedEventPayload, } from '@metamask/keyring-api'; import { EthScopes, @@ -29,7 +32,7 @@ import type { KeyringAccountV1 } from './account'; import { migrateAccountV1, getScopesForAccountV1 } from './migrations'; import type { SnapKeyringAllowedActions, - SnapKeyringAllowedEvents, + SnapKeyringEvents, SnapKeyringMessenger, } from './SnapKeyringMessenger'; @@ -63,50 +66,6 @@ function noScopes(account: KeyringAccount): KeyringAccountV1 { return accountV1; } -/* -class MockMessenger { - readonly #messenger: SnapKeyringMessenger; - - get: jest.Mock = jest.fn(); - - handleRequest: jest.Mock = jest.fn(); - - constructor( - messenger: ControllerMessenger< - SnapKeyringAllowedActions, - SnapKeyringAllowedEvents - >, - ) { - messenger.registerActionHandler('SnapController:get', this.get); - messenger.registerActionHandler( - 'SnapController:handleRequest', - this.handleRequest, - ); - - this.#messenger = messenger.getRestricted({ - name: 'MockSnapKeyringMessenger', - allowedEvents: [], - allowedActions: ['SnapController:get', 'SnapController:handleRequest'], - }); - } - - getMessenger(): SnapKeyringMessenger { - return this.#messenger; - } - - call(action: string, ...args: any): unknown { - switch (action) { - case 'SnapController:get': - return this.get(...args); - case 'SnapController:handleRequest': - return this.handleRequest(...args); - default: - throw new Error(`Unexpected action call: ${action}`); - } - } -} -*/ - describe('SnapKeyring', () => { let keyring: SnapKeyring; @@ -226,7 +185,7 @@ describe('SnapKeyring', () => { // Fake the ControllerMessenger and registers all mock actions here: const controllerMessenger: ControllerMessenger< SnapKeyringAllowedActions, - SnapKeyringAllowedEvents + SnapKeyringEvents > = new ControllerMessenger(); controllerMessenger.registerActionHandler( 'SnapController:get', @@ -240,7 +199,7 @@ describe('SnapKeyring', () => { // Now extracts a rectricted messenger for the Snap keyring only. const mockSnapKeyringMessenger: SnapKeyringMessenger = controllerMessenger.getRestricted({ - name: 'MockSnapKeyringMessenger', + name: 'SnapKeyring', allowedEvents: [], allowedActions: ['SnapController:get', 'SnapController:handleRequest'], }); @@ -491,6 +450,109 @@ describe('SnapKeyring', () => { 'Account scopes is required for non-EVM and ERC4337 accounts', ); }); + + it('receives an account balances update event and re-publish it to the messenger', async () => { + const mockPublishedEventCallback = jest.fn(); + mockSnapKeyringMessenger.subscribe( + 'SnapKeyring:accountBalancesUpdated', + mockPublishedEventCallback, + ); + + const account = ethEoaAccount1; + const event: AccountBalancesUpdatedEventPayload = { + balances: { + [account.id]: { + 'bip122:000000000019d6689c085ae165831e93/slip44:0': { + amount: '0.1', + unit: 'BTC', + }, + }, + }, + }; + + await keyring.handleKeyringSnapMessage(snapId, { + method: KeyringEvent.AccountBalancesUpdated, + params: event, + }); + expect(mockPublishedEventCallback).toHaveBeenCalledWith(event); + }); + + it('receives an transactions update event and re-publish it to the messenger', async () => { + const mockPublishedEventCallback = jest.fn(); + mockSnapKeyringMessenger.subscribe( + 'SnapKeyring:accountTransactionsUpdated', + mockPublishedEventCallback, + ); + + const account = ethEoaAccount1; + const event: AccountTransactionsUpdatedEventPayload = { + transactions: { + [account.id]: [ + { + id: 'f5d8ee39a430901c91a5917b9f2dc19d6d1a0e9cea205b009ca73dd04470b9a6', + timestamp: null, + chain: 'eip155:1', + status: 'submitted', + type: 'receive', + account: '5cd17616-ea18-4d72-974f-6dbaa3c56d15', + from: [], + to: [], + fees: [ + { + type: 'base', + asset: { + fungible: true, + type: 'eip155:1/slip44:60', + unit: 'ETH', + amount: '0.0001', + }, + }, + { + type: 'priority', + asset: { + fungible: true, + type: 'eip155:1/slip44:60', + unit: 'ETH', + amount: '0.0001', + }, + }, + ], + events: [], + }, + ], + }, + }; + + await keyring.handleKeyringSnapMessage(snapId, { + method: KeyringEvent.AccountTransactionsUpdated, + params: event, + }); + expect(mockPublishedEventCallback).toHaveBeenCalledWith(event); + }); + + it('receives an asset list update event and re-publish it to the messenger', async () => { + const mockPublishedEventCallback = jest.fn(); + mockSnapKeyringMessenger.subscribe( + 'SnapKeyring:accountAssetListUpdated', + mockPublishedEventCallback, + ); + + const account = ethEoaAccount1; + const event: AccountAssetListUpdatedEventPayload = { + assets: { + [account.id]: { + added: ['bip122:000000000019d6689c085ae165831e93/slip44:0'], + removed: ['bip122:000000000933ea01ad0ee984209779ba/slip44:0'], + }, + }, + }; + + await keyring.handleKeyringSnapMessage(snapId, { + method: KeyringEvent.AccountAssetListUpdated, + params: event, + }); + expect(mockPublishedEventCallback).toHaveBeenCalledWith(event); + }); }); describe('#handleAccountUpdated', () => { diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.ts b/packages/keyring-snap-bridge/src/SnapKeyring.ts index 43a2c404..4783a5c5 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.ts @@ -4,6 +4,7 @@ import type { TypedTransaction } from '@ethereumjs/tx'; import { TransactionFactory } from '@ethereumjs/tx'; +import type { ExtractEventPayload } from '@metamask/base-controller'; import type { TypedDataV1, TypedMessage } from '@metamask/eth-sig-util'; import { SignTypedDataVersion } from '@metamask/eth-sig-util'; import { @@ -13,6 +14,9 @@ import { EthUserOperationPatchStruct, isEvmAccountType, KeyringEvent, + AccountAssetListUpdatedEventStruct, + AccountBalancesUpdatedEventStruct, + AccountTransactionsUpdatedEventStruct, } from '@metamask/keyring-api'; import type { KeyringAccount, @@ -54,7 +58,10 @@ import { transformAccountV1, } from './migrations'; import { SnapIdMap } from './SnapIdMap'; -import type { SnapKeyringMessenger } from './SnapKeyringMessenger'; +import type { + SnapKeyringEvents, + SnapKeyringMessenger, +} from './SnapKeyringMessenger'; import type { SnapMessage } from './types'; import { SnapMessageStruct } from './types'; import { @@ -349,6 +356,65 @@ export class SnapKeyring extends EventEmitter { return null; } + /** + * Re-publish an account event. + * + * @param event - The event type. This is a unique identifier for this event. + * @param payload - The event payload. The type of the parameters for each event handler must + * match the type of this payload. + * @template EventType - A Snap keyring event type. + * @returns `null`. + */ + async #rePublishAccountEvent( + event: EventType, + ...payload: ExtractEventPayload + ): Promise { + this.#messenger.publish(event, ...payload); + return null; + } + + /** + * Handle a balances updated event from a Snap. + * + * @param message - Event message. + * @returns `null`. + */ + async #handleAccountBalancesUpdated(message: SnapMessage): Promise { + assert(message, AccountBalancesUpdatedEventStruct); + return this.#rePublishAccountEvent( + 'SnapKeyring:accountBalancesUpdated', + message.params, + ); + } + + /** + * Handle a asset list updated event from a Snap. + * + * @param message - Event message. + * @returns `null`. + */ + async #handleAccountAssetListUpdated(message: SnapMessage): Promise { + assert(message, AccountAssetListUpdatedEventStruct); + return this.#rePublishAccountEvent( + 'SnapKeyring:accountAssetListUpdated', + message.params, + ); + } + + /** + * Handle a transactions updated event from a Snap. + * + * @param message - Event message. + * @returns `null`. + */ + async #handleAccountTransactionsUpdated(message: SnapMessage): Promise { + assert(message, AccountTransactionsUpdatedEventStruct); + return this.#rePublishAccountEvent( + 'SnapKeyring:accountTransactionsUpdated', + message.params, + ); + } + /** * Handle a message from a Snap. * @@ -382,6 +448,19 @@ export class SnapKeyring extends EventEmitter { return this.#handleRequestRejected(snapId, message); } + // Assets related events: + case `${KeyringEvent.AccountBalancesUpdated}`: { + return this.#handleAccountBalancesUpdated(message); + } + + case `${KeyringEvent.AccountAssetListUpdated}`: { + return this.#handleAccountAssetListUpdated(message); + } + + case `${KeyringEvent.AccountTransactionsUpdated}`: { + return this.#handleAccountTransactionsUpdated(message); + } + default: throw new Error(`Method not supported: ${message.method}`); } diff --git a/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts b/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts index 9932b367..8f1e4226 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyringMessenger.ts @@ -1,14 +1,42 @@ import type { RestrictedControllerMessenger } from '@metamask/base-controller'; +import type { + AccountAssetListUpdatedEventPayload, + AccountBalancesUpdatedEventPayload, + AccountTransactionsUpdatedEventPayload, +} from '@metamask/keyring-api'; import type { HandleSnapRequest, GetSnap } from '@metamask/snaps-controllers'; -export type SnapKeyringAllowedActions = HandleSnapRequest | GetSnap; +export type SnapKeyringGetAccountsAction = { + type: `SnapKeyring:getAccounts`; + handler: () => string[]; +}; + +export type SnapKeyringAccountBalancesUpdatedEvent = { + type: `SnapKeyring:accountBalancesUpdated`; + payload: [AccountBalancesUpdatedEventPayload]; +}; + +export type SnapKeyringAccountAssetListUpdatedEvent = { + type: `SnapKeyring:accountAssetListUpdated`; + payload: [AccountAssetListUpdatedEventPayload]; +}; -export type SnapKeyringAllowedEvents = never; +export type SnapKeyringAccountTransactionsUpdatedEvent = { + type: `SnapKeyring:accountTransactionsUpdated`; + payload: [AccountTransactionsUpdatedEventPayload]; +}; + +export type SnapKeyringEvents = + | SnapKeyringAccountAssetListUpdatedEvent + | SnapKeyringAccountBalancesUpdatedEvent + | SnapKeyringAccountTransactionsUpdatedEvent; + +export type SnapKeyringAllowedActions = HandleSnapRequest | GetSnap; export type SnapKeyringMessenger = RestrictedControllerMessenger< - 'SnapKeyringMessenger', + 'SnapKeyring', SnapKeyringAllowedActions, - SnapKeyringAllowedEvents, + SnapKeyringEvents, SnapKeyringAllowedActions['type'], - SnapKeyringAllowedEvents['type'] + never >; diff --git a/packages/keyring-snap-bridge/src/index.ts b/packages/keyring-snap-bridge/src/index.ts index d01d020e..ceb4da7e 100644 --- a/packages/keyring-snap-bridge/src/index.ts +++ b/packages/keyring-snap-bridge/src/index.ts @@ -1,2 +1,3 @@ export * from './types'; export * from './SnapKeyring'; +export type * from './SnapKeyringMessenger'; diff --git a/packages/keyring-utils/src/types.ts b/packages/keyring-utils/src/types.ts index f00db535..89d2dde6 100644 --- a/packages/keyring-utils/src/types.ts +++ b/packages/keyring-utils/src/types.ts @@ -9,6 +9,10 @@ export const UuidStruct = definePattern( 'UuidV4', /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu, ); +/** + * Account ID (UUIDv4). + */ +export const AccountIdStruct = UuidStruct; // Alias for better naming purposes. /** * Validates if a given value is a valid URL. From 3eae7aa0ae3b058bdf891f2b75f5f7d9824e32c0 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Fri, 24 Jan 2025 17:53:40 +0100 Subject: [PATCH 6/8] fix!: make `scopes` more restrictive (#159) Adding a more restricted `scopes` field to each account type definitions (`Struct`). --------- Co-authored-by: Daniel Rocha <68558152+danroc@users.noreply.github.com> --- packages/keyring-api/src/api/account.ts | 2 +- packages/keyring-api/src/btc/types.test.ts | 38 +++++++++- packages/keyring-api/src/btc/types.ts | 17 ++++- packages/keyring-api/src/eth/constants.ts | 1 + packages/keyring-api/src/eth/types.ts | 6 ++ packages/keyring-api/src/sol/types.ts | 8 +- .../src/SnapKeyring.test.ts | 18 ++--- .../keyring-snap-bridge/src/SnapKeyring.ts | 17 ++--- .../keyring-snap-bridge/src/account.test.ts | 18 +++++ packages/keyring-snap-bridge/src/account.ts | 73 ++++++++++++++++++- .../keyring-snap-bridge/src/migrations/v1.ts | 33 +++++---- 11 files changed, 189 insertions(+), 42 deletions(-) create mode 100644 packages/keyring-snap-bridge/src/account.test.ts diff --git a/packages/keyring-api/src/api/account.ts b/packages/keyring-api/src/api/account.ts index f0cc4661..0a09a66a 100644 --- a/packages/keyring-api/src/api/account.ts +++ b/packages/keyring-api/src/api/account.ts @@ -74,7 +74,7 @@ export const KeyringAccountStruct = object({ address: string(), /** - * Account supported scopes (CAIP-2 chain IDs). + * Account supported scopes (CAIP-2 chain IDs or CAIP-2 namespaces). */ scopes: nonempty(array(union([CaipNamespaceStruct, CaipChainIdStruct]))), diff --git a/packages/keyring-api/src/btc/types.test.ts b/packages/keyring-api/src/btc/types.test.ts index 480a561a..01e9ea45 100644 --- a/packages/keyring-api/src/btc/types.test.ts +++ b/packages/keyring-api/src/btc/types.test.ts @@ -1,4 +1,20 @@ -import { BtcP2wpkhAddressStruct } from './types'; +import { BtcScopes } from './constants'; +import type { BtcP2wpkhAccount } from './types'; +import { + BtcMethod, + BtcP2wpkhAccountStruct, + BtcP2wpkhAddressStruct, +} from './types'; +import { BtcAccountType } from '../api'; + +const MOCK_ACCOUNT = { + id: '55583f38-d81b-48f8-8494-fc543c2b5c95', + type: BtcAccountType.P2wpkh, + address: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', + methods: [BtcMethod.SendBitcoin], + options: {}, + scopes: [BtcScopes.Mainnet], +}; describe('types', () => { describe('BtcP2wpkhAddressStruct', () => { @@ -37,5 +53,25 @@ describe('types', () => { `${errorPrefix}: No separator character for ${address}`, ); }); + + it('throws an error if there are multiple scopes', () => { + const account: BtcP2wpkhAccount = { + ...MOCK_ACCOUNT, + scopes: [BtcScopes.Mainnet, BtcScopes.Testnet], + }; + expect(() => BtcP2wpkhAccountStruct.assert(account)).toThrow( + 'At path: scopes -- Expected a array with a length of `1` but received one with a length of `2`', + ); + }); + + it('throws an error if there is no scope', () => { + const account: BtcP2wpkhAccount = { + ...MOCK_ACCOUNT, + scopes: [], + }; + expect(() => BtcP2wpkhAccountStruct.assert(account)).toThrow( + 'At path: scopes -- Expected a array with a length of `1` but received one with a length of `0`', + ); + }); }); }); diff --git a/packages/keyring-api/src/btc/types.ts b/packages/keyring-api/src/btc/types.ts index f610293d..d24f53cd 100644 --- a/packages/keyring-api/src/btc/types.ts +++ b/packages/keyring-api/src/btc/types.ts @@ -1,6 +1,14 @@ import { object } from '@metamask/keyring-utils'; import type { Infer } from '@metamask/superstruct'; -import { string, array, enums, refine, literal } from '@metamask/superstruct'; +import { + string, + array, + enums, + refine, + literal, + size, +} from '@metamask/superstruct'; +import { CaipChainIdStruct } from '@metamask/utils'; import { bech32 } from 'bech32'; import { BtcAccountType, KeyringAccountStruct } from '../api'; @@ -41,6 +49,13 @@ export const BtcP2wpkhAccountStruct = object({ */ type: literal(`${BtcAccountType.P2wpkh}`), + /** + * Account supported scope (CAIP-2 chain ID). + * + * NOTE: We consider a Bitcoin address to be valid on only 1 network at time. + */ + scopes: size(array(CaipChainIdStruct), 1), + /** * Account supported methods. */ diff --git a/packages/keyring-api/src/eth/constants.ts b/packages/keyring-api/src/eth/constants.ts index 2ba369d7..c37e0da0 100644 --- a/packages/keyring-api/src/eth/constants.ts +++ b/packages/keyring-api/src/eth/constants.ts @@ -6,4 +6,5 @@ export enum EthScopes { Namespace = 'eip155', Mainnet = 'eip155:1', + Testnet = 'eip155:11155111', } diff --git a/packages/keyring-api/src/eth/types.ts b/packages/keyring-api/src/eth/types.ts index e52993fa..20b85d0f 100644 --- a/packages/keyring-api/src/eth/types.ts +++ b/packages/keyring-api/src/eth/types.ts @@ -1,6 +1,7 @@ import { object, definePattern } from '@metamask/keyring-utils'; import type { Infer } from '@metamask/superstruct'; import { nonempty, array, enums, literal } from '@metamask/superstruct'; +import { CaipChainIdStruct } from '@metamask/utils'; import { EthScopes } from '.'; import { EthAccountType, KeyringAccountStruct } from '../api'; @@ -82,6 +83,11 @@ export const EthErc4337AccountStruct = object({ */ type: literal(`${EthAccountType.Erc4337}`), + /** + * Account supported scopes (CAIP-2 chain IDs). + */ + scopes: nonempty(array(CaipChainIdStruct)), + /** * Account supported methods. */ diff --git a/packages/keyring-api/src/sol/types.ts b/packages/keyring-api/src/sol/types.ts index 64dcaa66..da8caffd 100644 --- a/packages/keyring-api/src/sol/types.ts +++ b/packages/keyring-api/src/sol/types.ts @@ -1,6 +1,7 @@ import { object, definePattern } from '@metamask/keyring-utils'; import type { Infer } from '@metamask/superstruct'; -import { array, enums, literal } from '@metamask/superstruct'; +import { array, enums, literal, nonempty } from '@metamask/superstruct'; +import { CaipChainIdStruct } from '@metamask/utils'; import { KeyringAccountStruct, SolAccountType } from '../api'; @@ -35,6 +36,11 @@ export const SolDataAccountStruct = object({ */ type: literal(`${SolAccountType.DataAccount}`), + /** + * Account supported scopes (CAIP-2 chain IDs). + */ + scopes: nonempty(array(CaipChainIdStruct)), + /** * Account supported methods. */ diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts index 1c61145d..4f09d150 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts @@ -117,7 +117,7 @@ describe('SnapKeyring', () => { }; const ethEoaAccount3 = { id: 'c6697bcf-5710-4751-a1cb-340e4b50617a', - address: '0xab1G3q98V7C67T9103g30C0417610237A137d763'.toLowerCase(), + address: '0xf7bDe8609231033c69E502C08f85153f8A1548F2'.toLowerCase(), options: {}, methods: ETH_EOA_METHODS, scopes: [EthScopes.Namespace], @@ -128,7 +128,7 @@ describe('SnapKeyring', () => { address: '0x2f15b30952aebe0ed5fdbfe5bf16fb9ecdb31d9a'.toLowerCase(), options: {}, methods: ETH_4337_METHODS, - scopes: [EthScopes.Namespace], + scopes: [EthScopes.Testnet], type: EthAccountType.Erc4337, }; const btcP2wpkhAccount = { @@ -163,7 +163,7 @@ describe('SnapKeyring', () => { // For unknown accounts, we consider them as EVM EOA for now, so just re-use the // same scopes. scopes: [EthScopes.Namespace], - // This should be really possible to create such account, but since we potentially + // This should not be really possible to create such account, but since we potentially // migrate data upon the Snap keyring initialization, we want to cover edge-cases // like this one to avoid crashing and blocking everything... type: 'unknown:type' as KeyringAccount['type'], @@ -312,7 +312,7 @@ describe('SnapKeyring', () => { params: { account: { ...(ethEoaAccount1 as unknown as KeyringAccount), - address: '0x0', + address: ethEoaAccount2.address, }, }, }), @@ -447,7 +447,7 @@ describe('SnapKeyring', () => { }, }), ).rejects.toThrow( - 'Account scopes is required for non-EVM and ERC4337 accounts', + 'At path: scopes -- Expected an array value, but received: undefined', ); }); @@ -633,7 +633,7 @@ describe('SnapKeyring', () => { it('fails when the EthMethod is not supported after update', async () => { // Update first account to remove `EthMethod.PersonalSign` - let updatedMethods: EthMethod[] = Object.values(EthMethod).filter( + let updatedMethods: EthMethod[] = Object.values(ETH_EOA_METHODS).filter( (method) => method !== EthMethod.PersonalSign, ); expect( @@ -656,7 +656,7 @@ describe('SnapKeyring', () => { `Method '${EthMethod.PersonalSign}' not supported for account ${ethEoaAccount1.address}`, ); // Restore `EthMethod.PersonalSign` and remove `EthMethod.SignTransaction` - updatedMethods = Object.values(EthMethod).filter( + updatedMethods = Object.values(ETH_EOA_METHODS).filter( (method) => method !== EthMethod.SignTransaction, ); expect( @@ -723,7 +723,7 @@ describe('SnapKeyring', () => { params: { account }, }), ).rejects.toThrow( - 'Account scopes is required for non-EVM and ERC4337 accounts', + 'At path: scopes -- Expected an array value, but received: undefined', ); }); @@ -740,7 +740,7 @@ describe('SnapKeyring', () => { params: { account }, }), ).rejects.toThrow( - 'Account scopes is required for non-EVM and ERC4337 accounts', + 'At path: scopes -- Expected an array value, but received: undefined', ); }); }); diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.ts b/packages/keyring-snap-bridge/src/SnapKeyring.ts index 4783a5c5..d76d4b40 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.ts @@ -43,6 +43,7 @@ import { import { EventEmitter } from 'events'; import { v4 as uuid } from 'uuid'; +import { transformAccount } from './account'; import { DeferredPromise } from './DeferredPromise'; import { AccountCreatedEventStruct, @@ -52,11 +53,7 @@ import { RequestRejectedEventStruct, } from './events'; import { projectLogger as log } from './logger'; -import { - isAccountV1, - migrateAccountV1, - transformAccountV1, -} from './migrations'; +import { isAccountV1, migrateAccountV1 } from './migrations'; import { SnapIdMap } from './SnapIdMap'; import type { SnapKeyringEvents, @@ -208,9 +205,8 @@ export class SnapKeyring extends EventEmitter { displayConfirmation, } = message.params; - // To keep the retro-compatibility with older keyring-api versions, we mark some fields - // as optional and provide them here if they are missing. - const account = transformAccountV1(newAccountFromEvent); + // Potentially migrate the account. + const account = transformAccount(newAccountFromEvent); // The UI still uses the account address to identify accounts, so we need // to block the creation of duplicate accounts for now to prevent accounts @@ -258,9 +254,8 @@ export class SnapKeyring extends EventEmitter { this.#accounts.get(snapId, newAccountFromEvent.id) ?? throwError(`Account '${newAccountFromEvent.id}' not found`); - // To keep the retro-compatibility with older keyring-api versions, we mark some fields - // as optional and provide them here if they are missing. - const newAccount = transformAccountV1(newAccountFromEvent); + // Potentially migrate the account. + const newAccount = transformAccount(newAccountFromEvent); // The address of the account cannot be changed. In the future, we will // support changing the address of an account since it will be required to diff --git a/packages/keyring-snap-bridge/src/account.test.ts b/packages/keyring-snap-bridge/src/account.test.ts new file mode 100644 index 00000000..d56d62cc --- /dev/null +++ b/packages/keyring-snap-bridge/src/account.test.ts @@ -0,0 +1,18 @@ +import type { KeyringAccount } from '@metamask/keyring-api'; + +import { transformAccount } from './account'; + +describe('account', () => { + it('throws for unknown account type', () => { + const unknownAccount = { + // This should not be really possible to create such account, but since we potentially + // migrate data upon the Snap keyring initialization, we want to cover edge-cases + // like this one to avoid crashing and blocking everything... + type: 'unknown:type', + } as unknown as KeyringAccount; // Just testing the default case. + + expect(() => transformAccount(unknownAccount)).toThrow( + "Unknown account type: 'unknown:type'", + ); + }); +}); diff --git a/packages/keyring-snap-bridge/src/account.ts b/packages/keyring-snap-bridge/src/account.ts index 74c7bae1..69d0d974 100644 --- a/packages/keyring-snap-bridge/src/account.ts +++ b/packages/keyring-snap-bridge/src/account.ts @@ -1,5 +1,17 @@ -import { KeyringAccountStruct } from '@metamask/keyring-api'; -import { omit, type Infer } from '@metamask/superstruct'; +import type { KeyringAccount, KeyringAccountType } from '@metamask/keyring-api'; +import { + BtcAccountType, + BtcP2wpkhAccountStruct, + EthAccountType, + EthEoaAccountStruct, + EthErc4337AccountStruct, + KeyringAccountStruct, + SolAccountType, + SolDataAccountStruct, +} from '@metamask/keyring-api'; +import { assert, omit, type Infer } from '@metamask/superstruct'; + +import { isAccountV1, transformAccountV1 } from './migrations'; /** * A `KeyringAccount` with some optional fields which can be used to keep @@ -8,3 +20,60 @@ import { omit, type Infer } from '@metamask/superstruct'; export const KeyringAccountV1Struct = omit(KeyringAccountStruct, ['scopes']); export type KeyringAccountV1 = Infer; + +/** + * Assert that an account-like object matches its actual account type. + * + * @param account - The account-like object. + * @returns The account as normal `KeyringAccount`. + */ +export function assertKeyringAccount< + Account extends { type: KeyringAccountType }, +>(account: Account): KeyringAccount { + // TODO: We should use a `selectiveUnion` for this and probably use it to define + // the `KeyringAccount`. This would also required to have a "generic `KeyringAccount`" + // definition. + switch (account.type) { + case BtcAccountType.P2wpkh: { + assert(account, BtcP2wpkhAccountStruct); + return account; + } + case SolAccountType.DataAccount: { + assert(account, SolDataAccountStruct); + return account; + } + case EthAccountType.Erc4337: { + assert(account, EthErc4337AccountStruct); + return account; + } + case EthAccountType.Eoa: { + assert(account, EthEoaAccountStruct); + return account; + } + default: { + // For now, we cannot much more than this (this should also, never happen)! + // NOTE: We could use a "generic `KeyringAccount` type" here though. + throw new Error(`Unknown account type: '${account.type}'`); + } + } +} + +/** + * Transform any versionned account to a `KeyringAccount`. + * + * @param accountToTransform - The account to transform. + * @returns A valid transformed `KeyringAccount`. + */ +export function transformAccount( + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents + accountToTransform: KeyringAccountV1 | KeyringAccount, +): KeyringAccount { + // To keep the retro-compatibility with older keyring-api versions, we identify the account's + // version and transform it to the latest `KeyringAccount` representation. + const account = isAccountV1(accountToTransform) + ? transformAccountV1(accountToTransform) + : accountToTransform; + + // We still assert that the converted account is valid according to their account's type. + return assertKeyringAccount(account); +} diff --git a/packages/keyring-snap-bridge/src/migrations/v1.ts b/packages/keyring-snap-bridge/src/migrations/v1.ts index d99e362c..b69b4709 100644 --- a/packages/keyring-snap-bridge/src/migrations/v1.ts +++ b/packages/keyring-snap-bridge/src/migrations/v1.ts @@ -10,7 +10,11 @@ import { import { isBtcMainnetAddress } from '@metamask/keyring-utils'; import { is } from '@metamask/superstruct'; -import { KeyringAccountV1Struct, type KeyringAccountV1 } from '../account'; +import { + assertKeyringAccount, + KeyringAccountV1Struct, + type KeyringAccountV1, +} from '../account'; /** * Checks if an account is an `KeyringAccount` v1. @@ -40,10 +44,11 @@ export function getScopesForAccountV1(accountV1: KeyringAccountV1): string[] { } case EthAccountType.Erc4337: { // EVM Erc4337 account - // NOTE: A Smart Contract account might not be compatible with every chain, but we still use - // "generic" scope for now. Also, there's no official Snap as of today that uses this account type. So - // this case should never happen. - return [EthScopes.Namespace]; + // NOTE: A Smart Contract account might not be compatible with every chain, in this case we just default + // to testnet since we cannot really "guess" it from here. + // Also, there's no official Snap as of today that uses this account type. So this case should never happen + // in production. + return [EthScopes.Testnet]; } case BtcAccountType.P2wpkh: { // Bitcoin uses different accounts for testnet and mainnet @@ -77,24 +82,20 @@ export function transformAccountV1( ): KeyringAccount { const { type } = accountV1; - if (!isAccountV1(accountV1)) { - // Nothing to do in this case. - return accountV1 as KeyringAccount; - } - + // EVM EOA account are compatible with any EVM networks, and we use CAIP-2 + // namespaces when the scope relates to ALL chains (from that namespace). + // So we can automatically inject a valid `scopes` for this, but not for + // other kind of accounts. if (type === EthAccountType.Eoa) { - // EVM EOA account are compatible with any EVM networks, and we use CAIP-2 - // namespaces when the scope relates to ALL chains (from that namespace). return { ...accountV1, scopes: getScopesForAccountV1(accountV1), }; } - // For all non-EVM Snaps and ERC4337 Snaps, the scopes is required. - throw new Error( - `Account scopes is required for non-EVM and ERC4337 accounts`, - ); + // For all other non-EVM and ERC4337 Snap accounts, the `scopes` is required, and + // each `*AccountStruct` should assert that automatically. + return assertKeyringAccount(accountV1); } /** From 4833acc24796246abcdfb0d504371c2eb9489fde Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Fri, 24 Jan 2025 18:36:17 +0100 Subject: [PATCH 7/8] release: 23.0.0 (#160) # Description This is the release candidate for version 23.0.0. See the CHANGELOGs for more details. --- package.json | 2 +- packages/keyring-api/CHANGELOG.md | 13 ++++++++++++- packages/keyring-api/package.json | 2 +- packages/keyring-internal-api/CHANGELOG.md | 10 +++++++++- packages/keyring-internal-api/package.json | 2 +- .../keyring-internal-snap-client/CHANGELOG.md | 10 +++++++++- .../keyring-internal-snap-client/package.json | 2 +- packages/keyring-snap-bridge/CHANGELOG.md | 16 +++++++++++++++- packages/keyring-snap-bridge/package.json | 2 +- packages/keyring-snap-client/CHANGELOG.md | 9 ++++++++- packages/keyring-snap-client/package.json | 2 +- packages/keyring-utils/CHANGELOG.md | 9 ++++++++- packages/keyring-utils/package.json | 2 +- 13 files changed, 68 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 191b3806..5e041374 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/accounts-monorepo", - "version": "22.0.0", + "version": "23.0.0", "private": true, "description": "Monorepo for MetaMask accounts related packages", "repository": { diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index c37f3ea0..ab9b0c44 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [15.0.0] + +### Added + +- Add `account{AssetList,Balances,Transactions}UpdatedEventStruct` keyring events ([#154](https://github.com/MetaMask/accounts/pull/154)) + +### Changed + +- **BREAKING:** Make specific `*AccountStruct.scopes` more strict ([#159](https://github.com/MetaMask/accounts/pull/159)) + ## [14.0.0] ### Added @@ -477,7 +487,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SnapController keyring client. It is intended to be used by MetaMask to talk to the snap. - Helper functions to create keyring handler in the snap. -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@14.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@15.0.0...HEAD +[15.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@14.0.0...@metamask/keyring-api@15.0.0 [14.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@13.0.0...@metamask/keyring-api@14.0.0 [13.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@12.0.0...@metamask/keyring-api@13.0.0 [12.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-api@11.1.0...@metamask/keyring-api@12.0.0 diff --git a/packages/keyring-api/package.json b/packages/keyring-api/package.json index 6948e7cf..90131955 100644 --- a/packages/keyring-api/package.json +++ b/packages/keyring-api/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-api", - "version": "14.0.0", + "version": "15.0.0", "description": "MetaMask Keyring API", "keywords": [ "metamask", diff --git a/packages/keyring-internal-api/CHANGELOG.md b/packages/keyring-internal-api/CHANGELOG.md index 740512bb..0bcc0c15 100644 --- a/packages/keyring-internal-api/CHANGELOG.md +++ b/packages/keyring-internal-api/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.0] + +### Changed + +- **BREAKING:** Bump `@metamask/keyring-api` from `^14.0.0` to `^15.0.0` ([#160](https://github.com/MetaMask/accounts/pull/160)) + - The `scopes` from each `*AccountStruct` types is now more strict which impact all `Internal*AccountStruct` types. + ## [2.0.1] ### Changed @@ -35,7 +42,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.1...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@3.0.0...HEAD +[3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.1...@metamask/keyring-internal-api@3.0.0 [2.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@2.0.0...@metamask/keyring-internal-api@2.0.1 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@1.1.0...@metamask/keyring-internal-api@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-api@1.0.0...@metamask/keyring-internal-api@1.1.0 diff --git a/packages/keyring-internal-api/package.json b/packages/keyring-internal-api/package.json index 5483db50..51bd3369 100644 --- a/packages/keyring-internal-api/package.json +++ b/packages/keyring-internal-api/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-internal-api", - "version": "2.0.1", + "version": "3.0.0", "description": "MetaMask Keyring Internal API", "keywords": [ "metamask", diff --git a/packages/keyring-internal-snap-client/CHANGELOG.md b/packages/keyring-internal-snap-client/CHANGELOG.md index 761e3b04..04dd69a1 100644 --- a/packages/keyring-internal-snap-client/CHANGELOG.md +++ b/packages/keyring-internal-snap-client/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.1] + +### Changed + +- Bump `@metamask/keyring-api` from `^14.0.0` to `^15.0.0` ([#160](https://github.com/MetaMask/accounts/pull/160)) +- Bump `@metamask/keyring-snap-client` from `^3.0.0` to `^3.0.1` ([#160](https://github.com/MetaMask/accounts/pull/160)) + ## [3.0.0] ### Added @@ -45,7 +52,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@3.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@3.0.1...HEAD +[3.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@3.0.0...@metamask/keyring-internal-snap-client@3.0.1 [3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@2.0.0...@metamask/keyring-internal-snap-client@3.0.0 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@1.1.0...@metamask/keyring-internal-snap-client@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-internal-snap-client@1.0.0...@metamask/keyring-internal-snap-client@1.1.0 diff --git a/packages/keyring-internal-snap-client/package.json b/packages/keyring-internal-snap-client/package.json index 288c6915..1f766cf8 100644 --- a/packages/keyring-internal-snap-client/package.json +++ b/packages/keyring-internal-snap-client/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-internal-snap-client", - "version": "3.0.0", + "version": "3.0.1", "description": "MetaMask Keyring Snap internal clients", "keywords": [ "metamask", diff --git a/packages/keyring-snap-bridge/CHANGELOG.md b/packages/keyring-snap-bridge/CHANGELOG.md index 7673377e..4d7b1256 100644 --- a/packages/keyring-snap-bridge/CHANGELOG.md +++ b/packages/keyring-snap-bridge/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [9.0.0] + +### Added + +- Add `account{AssetList,Balances,Transactions}Updated` keyring events and re-publish them through the new `Messenger` ([#154](https://github.com/MetaMask/accounts/pull/154)) + +### Changed + +- **BREAKING:** Use `Messenger` instead of `SnapsController` ([#152](https://github.com/MetaMask/accounts/pull/152)) + - This allows to break the runtime dependency we had with some `snaps-*` pacakges. +- **BREAKING:** Make `scopes` more strict ([#159](https://github.com/MetaMask/accounts/pull/159)) + - We now use specific `*AccountStucts` when checking created/updated accounts to make the `scopes` sent by the Snap are valid regarding their account type definition. + ## [8.1.1] ### Changed @@ -416,7 +429,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release. -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.1...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@9.0.0...HEAD +[9.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.1...@metamask/eth-snap-keyring@9.0.0 [8.1.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.1.0...@metamask/eth-snap-keyring@8.1.1 [8.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@8.0.0...@metamask/eth-snap-keyring@8.1.0 [8.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@7.1.0...@metamask/eth-snap-keyring@8.0.0 diff --git a/packages/keyring-snap-bridge/package.json b/packages/keyring-snap-bridge/package.json index 996dcf6b..28b4f7ff 100644 --- a/packages/keyring-snap-bridge/package.json +++ b/packages/keyring-snap-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/eth-snap-keyring", - "version": "8.1.1", + "version": "9.0.0", "description": "Snaps keyring bridge.", "repository": { "type": "git", diff --git a/packages/keyring-snap-client/CHANGELOG.md b/packages/keyring-snap-client/CHANGELOG.md index 245e6176..844a573e 100644 --- a/packages/keyring-snap-client/CHANGELOG.md +++ b/packages/keyring-snap-client/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.1] + +### Changed + +- Bump `@metamask/keyring-api` from `^14.0.0` to `^15.0.0` ([#160](https://github.com/MetaMask/accounts/pull/160)) + ## [3.0.0] ### Added @@ -40,7 +46,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@3.0.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@3.0.1...HEAD +[3.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@3.0.0...@metamask/keyring-snap-client@3.0.1 [3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@2.0.0...@metamask/keyring-snap-client@3.0.0 [2.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@1.1.0...@metamask/keyring-snap-client@2.0.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-snap-client@1.0.0...@metamask/keyring-snap-client@1.1.0 diff --git a/packages/keyring-snap-client/package.json b/packages/keyring-snap-client/package.json index 4891074a..0a162fe1 100644 --- a/packages/keyring-snap-client/package.json +++ b/packages/keyring-snap-client/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-snap-client", - "version": "3.0.0", + "version": "3.0.1", "description": "MetaMask Keyring Snap clients", "keywords": [ "metamask", diff --git a/packages/keyring-utils/CHANGELOG.md b/packages/keyring-utils/CHANGELOG.md index a80dccb6..85e77a7b 100644 --- a/packages/keyring-utils/CHANGELOG.md +++ b/packages/keyring-utils/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.0] + +### Added + +- Add `AccountIdStruct` alias ([#154](https://github.com/MetaMask/accounts/pull/154)) + ## [1.2.0] ### Changed @@ -32,7 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This new version fixes a bug with CJS re-exports. - Initial release ([#24](https://github.com/MetaMask/accounts/pull/24)) -[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.2.0...HEAD +[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.3.0...HEAD +[1.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.2.0...@metamask/keyring-utils@1.3.0 [1.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.1.0...@metamask/keyring-utils@1.2.0 [1.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-utils@1.0.0...@metamask/keyring-utils@1.1.0 [1.0.0]: https://github.com/MetaMask/accounts/releases/tag/@metamask/keyring-utils@1.0.0 diff --git a/packages/keyring-utils/package.json b/packages/keyring-utils/package.json index 97ba7d9b..93b79223 100644 --- a/packages/keyring-utils/package.json +++ b/packages/keyring-utils/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/keyring-utils", - "version": "1.2.0", + "version": "1.3.0", "description": "MetaMask Keyring utils", "keywords": [ "metamask", From 063dfa4973c301363851bb626f8e9cb527dea4c6 Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Tue, 28 Jan 2025 14:13:11 +0100 Subject: [PATCH 8/8] refactor!: rename `*Scopes` enums to `*Scope` (#164) Rename all `*Scopes` enums to `*Scope` to match the pattern used for other enums. --- packages/keyring-api/src/btc/constants.ts | 2 +- packages/keyring-api/src/btc/types.test.ts | 6 +-- packages/keyring-api/src/eth/constants.ts | 2 +- packages/keyring-api/src/eth/types.ts | 4 +- packages/keyring-api/src/events.test.ts | 12 ++--- packages/keyring-api/src/sol/constants.ts | 2 +- .../src/SnapKeyring.test.ts | 44 +++++++++---------- .../keyring-snap-bridge/src/migrations/v1.ts | 18 ++++---- 8 files changed, 45 insertions(+), 45 deletions(-) diff --git a/packages/keyring-api/src/btc/constants.ts b/packages/keyring-api/src/btc/constants.ts index 954097ea..658611f6 100644 --- a/packages/keyring-api/src/btc/constants.ts +++ b/packages/keyring-api/src/btc/constants.ts @@ -3,7 +3,7 @@ /** * Scopes for Bitcoin account type. See {@link KeyringAccount.scopes}. */ -export enum BtcScopes { +export enum BtcScope { Namespace = 'bip122', Mainnet = 'bip122:000000000019d6689c085ae165831e93', Testnet = 'bip122:000000000933ea01ad0ee984209779ba', diff --git a/packages/keyring-api/src/btc/types.test.ts b/packages/keyring-api/src/btc/types.test.ts index 01e9ea45..329d0dd9 100644 --- a/packages/keyring-api/src/btc/types.test.ts +++ b/packages/keyring-api/src/btc/types.test.ts @@ -1,4 +1,4 @@ -import { BtcScopes } from './constants'; +import { BtcScope } from './constants'; import type { BtcP2wpkhAccount } from './types'; import { BtcMethod, @@ -13,7 +13,7 @@ const MOCK_ACCOUNT = { address: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', methods: [BtcMethod.SendBitcoin], options: {}, - scopes: [BtcScopes.Mainnet], + scopes: [BtcScope.Mainnet], }; describe('types', () => { @@ -57,7 +57,7 @@ describe('types', () => { it('throws an error if there are multiple scopes', () => { const account: BtcP2wpkhAccount = { ...MOCK_ACCOUNT, - scopes: [BtcScopes.Mainnet, BtcScopes.Testnet], + scopes: [BtcScope.Mainnet, BtcScope.Testnet], }; expect(() => BtcP2wpkhAccountStruct.assert(account)).toThrow( 'At path: scopes -- Expected a array with a length of `1` but received one with a length of `2`', diff --git a/packages/keyring-api/src/eth/constants.ts b/packages/keyring-api/src/eth/constants.ts index c37e0da0..65c120f6 100644 --- a/packages/keyring-api/src/eth/constants.ts +++ b/packages/keyring-api/src/eth/constants.ts @@ -3,7 +3,7 @@ /** * Scopes for EVM account type. See {@link KeyringAccount.scopes}. */ -export enum EthScopes { +export enum EthScope { Namespace = 'eip155', Mainnet = 'eip155:1', Testnet = 'eip155:11155111', diff --git a/packages/keyring-api/src/eth/types.ts b/packages/keyring-api/src/eth/types.ts index 20b85d0f..f08b0240 100644 --- a/packages/keyring-api/src/eth/types.ts +++ b/packages/keyring-api/src/eth/types.ts @@ -3,7 +3,7 @@ import type { Infer } from '@metamask/superstruct'; import { nonempty, array, enums, literal } from '@metamask/superstruct'; import { CaipChainIdStruct } from '@metamask/utils'; -import { EthScopes } from '.'; +import { EthScope } from '.'; import { EthAccountType, KeyringAccountStruct } from '../api'; export const EthBytesStruct = definePattern('EthBytes', /^0x[0-9a-f]*$/iu); @@ -51,7 +51,7 @@ export const EthEoaAccountStruct = object({ /** * Account scopes (must be ['eip155']). */ - scopes: nonempty(array(literal(EthScopes.Namespace))), + scopes: nonempty(array(literal(EthScope.Namespace))), /** * Account supported methods. diff --git a/packages/keyring-api/src/events.test.ts b/packages/keyring-api/src/events.test.ts index 4934f644..11d62f47 100644 --- a/packages/keyring-api/src/events.test.ts +++ b/packages/keyring-api/src/events.test.ts @@ -1,7 +1,7 @@ import { is } from '@metamask/superstruct'; import { EthAccountType } from './api'; -import { EthScopes } from './eth/constants'; +import { EthScope } from './eth/constants'; import { AccountCreatedEventStruct, AccountDeletedEventStruct, @@ -22,7 +22,7 @@ describe('events', () => { address: '0x0123', methods: [], options: {}, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }, }, @@ -40,7 +40,7 @@ describe('events', () => { address: '0x0123', methods: [], options: {}, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }, }, @@ -58,7 +58,7 @@ describe('events', () => { address: '0x0123', methods: [], options: {}, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }, displayConfirmation: true, @@ -79,7 +79,7 @@ describe('events', () => { address: '0x0123', methods: [], options: {}, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }, }, @@ -97,7 +97,7 @@ describe('events', () => { address: '0x0123', methods: [], options: {}, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }, }, diff --git a/packages/keyring-api/src/sol/constants.ts b/packages/keyring-api/src/sol/constants.ts index db6078cd..5bfc0536 100644 --- a/packages/keyring-api/src/sol/constants.ts +++ b/packages/keyring-api/src/sol/constants.ts @@ -3,7 +3,7 @@ /** * Scopes for Solana account type. See {@link KeyringAccount.scopes}. */ -export enum SolScopes { +export enum SolScope { Namespace = 'solana', Devnet = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', Mainnet = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', diff --git a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts index 4f09d150..c76b4222 100644 --- a/packages/keyring-snap-bridge/src/SnapKeyring.test.ts +++ b/packages/keyring-snap-bridge/src/SnapKeyring.test.ts @@ -12,7 +12,7 @@ import type { AccountAssetListUpdatedEventPayload, } from '@metamask/keyring-api'; import { - EthScopes, + EthScope, BtcAccountType, EthAccountType, SolAccountType, @@ -20,8 +20,8 @@ import { EthMethod, SolMethod, KeyringEvent, - BtcScopes, - SolScopes, + BtcScope, + SolScope, } from '@metamask/keyring-api'; import type { SnapId } from '@metamask/snaps-sdk'; import { toCaipChainId } from '@metamask/utils'; @@ -104,7 +104,7 @@ describe('SnapKeyring', () => { address: '0xC728514Df8A7F9271f4B7a4dd2Aa6d2D723d3eE3'.toLowerCase(), options: {}, methods: ETH_EOA_METHODS, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }; const ethEoaAccount2 = { @@ -112,7 +112,7 @@ describe('SnapKeyring', () => { address: '0x34b13912eAc00152bE0Cb409A301Ab8E55739e63'.toLowerCase(), options: {}, methods: ETH_EOA_METHODS, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }; const ethEoaAccount3 = { @@ -120,7 +120,7 @@ describe('SnapKeyring', () => { address: '0xf7bDe8609231033c69E502C08f85153f8A1548F2'.toLowerCase(), options: {}, methods: ETH_EOA_METHODS, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, }; const ethErc4337Account = { @@ -128,7 +128,7 @@ describe('SnapKeyring', () => { address: '0x2f15b30952aebe0ed5fdbfe5bf16fb9ecdb31d9a'.toLowerCase(), options: {}, methods: ETH_4337_METHODS, - scopes: [EthScopes.Testnet], + scopes: [EthScope.Testnet], type: EthAccountType.Erc4337, }; const btcP2wpkhAccount = { @@ -136,7 +136,7 @@ describe('SnapKeyring', () => { address: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', options: {}, methods: [...Object.values(BtcMethod)], - scopes: [BtcScopes.Mainnet], + scopes: [BtcScope.Mainnet], type: BtcAccountType.P2wpkh, }; const btcP2wpkhTestnetAccount = { @@ -144,7 +144,7 @@ describe('SnapKeyring', () => { address: 'tb1q6rmsq3vlfdhjdhtkxlqtuhhlr6pmj09y6w43g8', options: {}, methods: [...Object.values(BtcMethod)], - scopes: [BtcScopes.Testnet], + scopes: [BtcScope.Testnet], type: BtcAccountType.P2wpkh, }; const solDataAccount = { @@ -152,7 +152,7 @@ describe('SnapKeyring', () => { address: '3d4v35MRK57xM2Nte3E3rTQU1zyXGVrkXJ6FuEjVoKzM', options: {}, methods: [...Object.values(SolMethod)], - scopes: [SolScopes.Mainnet, SolScopes.Testnet, SolScopes.Devnet], + scopes: [SolScope.Mainnet, SolScope.Testnet, SolScope.Devnet], type: SolAccountType.DataAccount, }; const unknownAccount: KeyringAccount = { @@ -162,7 +162,7 @@ describe('SnapKeyring', () => { methods: [], // For unknown accounts, we consider them as EVM EOA for now, so just re-use the // same scopes. - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], // This should not be really possible to create such account, but since we potentially // migrate data upon the Snap keyring initialization, we want to cover edge-cases // like this one to avoid crashing and blocking everything... @@ -237,7 +237,7 @@ describe('SnapKeyring', () => { id: 'b05d918a-b37c-497a-bb28-3d15c0d56b7a', options: {}, methods: ETH_EOA_METHODS, - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], type: EthAccountType.Eoa, // Even checksummed address will be lower-cased by the bridge. address: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', @@ -429,7 +429,7 @@ describe('SnapKeyring', () => { metadata: expect.any(Object), // By default, new EVM accounts will have this scopes if it not provided // during the account creation flow. - scopes: [EthScopes.Namespace], + scopes: [EthScope.Namespace], }); }); @@ -707,7 +707,7 @@ describe('SnapKeyring', () => { const keyringAccounts = keyring.listAccounts(); expect(keyringAccounts.length).toBeGreaterThan(0); - expect(keyringAccounts[0]?.scopes).toStrictEqual([EthScopes.Namespace]); + expect(keyringAccounts[0]?.scopes).toStrictEqual([EthScope.Namespace]); }); it('updates a ERC4337 account with the no scope will throw an error', async () => { @@ -1044,7 +1044,7 @@ describe('SnapKeyring', () => { it('unknown v1 accounts scopes defaults to EOA scopes', () => { expect(getScopesForAccountV1(unknownAccount)).toStrictEqual([ - EthScopes.Namespace, + EthScope.Namespace, ]); }); }); @@ -1196,7 +1196,7 @@ describe('SnapKeyring', () => { }; const tx = TransactionFactory.fromTxData(mockTx); const expectedSignedTx = TransactionFactory.fromTxData(mockSignedTx); - const expectedScope = EthScopes.Mainnet; + const expectedScope = EthScope.Mainnet; mockMessenger.handleRequest.mockResolvedValue({ pending: false, @@ -1274,7 +1274,7 @@ describe('SnapKeyring', () => { }, }; - const expectedScope = EthScopes.Mainnet; + const expectedScope = EthScope.Mainnet; const expectedSignature = '0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c'; @@ -1472,7 +1472,7 @@ describe('SnapKeyring', () => { method: 'keyring_submitRequest', params: { id: expect.any(String), - scope: toCaipChainId(EthScopes.Namespace, executionContext.chainId), + scope: toCaipChainId(EthScope.Namespace, executionContext.chainId), account: ethErc4337Account.id, request: { method: 'eth_prepareUserOperation', @@ -1525,7 +1525,7 @@ describe('SnapKeyring', () => { method: 'keyring_submitRequest', params: { id: expect.any(String), - scope: toCaipChainId(EthScopes.Namespace, executionContext.chainId), + scope: toCaipChainId(EthScope.Namespace, executionContext.chainId), account: ethErc4337Account.id, request: { method: 'eth_patchUserOperation', @@ -1574,7 +1574,7 @@ describe('SnapKeyring', () => { method: 'keyring_submitRequest', params: { id: expect.any(String), - scope: toCaipChainId(EthScopes.Namespace, executionContext.chainId), + scope: toCaipChainId(EthScope.Namespace, executionContext.chainId), account: ethErc4337Account.id, request: { method: 'eth_signUserOperation', @@ -1799,7 +1799,7 @@ describe('SnapKeyring', () => { method: 'keyring_submitRequest', params: { id: expect.any(String), - scope: toCaipChainId(EthScopes.Namespace, executionContext.chainId), + scope: toCaipChainId(EthScope.Namespace, executionContext.chainId), account: ethErc4337Account.id, request: { method: 'eth_prepareUserOperation', @@ -1866,7 +1866,7 @@ describe('SnapKeyring', () => { method: 'keyring_submitRequest', params: { id: expect.any(String), - scope: toCaipChainId(EthScopes.Namespace, executionContext.chainId), + scope: toCaipChainId(EthScope.Namespace, executionContext.chainId), account: ethErc4337Account.id, request: { method: 'eth_patchUserOperation', diff --git a/packages/keyring-snap-bridge/src/migrations/v1.ts b/packages/keyring-snap-bridge/src/migrations/v1.ts index b69b4709..56dc9c02 100644 --- a/packages/keyring-snap-bridge/src/migrations/v1.ts +++ b/packages/keyring-snap-bridge/src/migrations/v1.ts @@ -1,10 +1,10 @@ import { BtcAccountType, - BtcScopes, + BtcScope, EthAccountType, - EthScopes, + EthScope, SolAccountType, - SolScopes, + SolScope, type KeyringAccount, } from '@metamask/keyring-api'; import { isBtcMainnetAddress } from '@metamask/keyring-utils'; @@ -40,7 +40,7 @@ export function getScopesForAccountV1(accountV1: KeyringAccountV1): string[] { case EthAccountType.Eoa: { // EVM EOA account are compatible with any EVM networks, and we use CAIP-2 // namespaces when the scope relates to ALL chains (from that namespace). - return [EthScopes.Namespace]; + return [EthScope.Namespace]; } case EthAccountType.Erc4337: { // EVM Erc4337 account @@ -48,23 +48,23 @@ export function getScopesForAccountV1(accountV1: KeyringAccountV1): string[] { // to testnet since we cannot really "guess" it from here. // Also, there's no official Snap as of today that uses this account type. So this case should never happen // in production. - return [EthScopes.Testnet]; + return [EthScope.Testnet]; } case BtcAccountType.P2wpkh: { // Bitcoin uses different accounts for testnet and mainnet return [ isBtcMainnetAddress(accountV1.address) - ? BtcScopes.Mainnet - : BtcScopes.Testnet, + ? BtcScope.Mainnet + : BtcScope.Testnet, ]; } case SolAccountType.DataAccount: { // Solana account supports multiple chains. - return [SolScopes.Mainnet, SolScopes.Testnet, SolScopes.Devnet]; + return [SolScope.Mainnet, SolScope.Testnet, SolScope.Devnet]; } default: // We re-use EOA scopes if we don't know what to do for now. - return [EthScopes.Namespace]; + return [EthScope.Namespace]; } }