From bc5610499b0e4a4323bba69ff796edb0a432191e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 14:02:49 -0700 Subject: [PATCH 001/146] Initial package --- README.md | 28 +- packages/multichain/CHANGELOG.md | 10 + packages/multichain/LICENSE | 20 + packages/multichain/README.md | 15 + packages/multichain/jest.config.js | 26 + packages/multichain/package.json | 59 ++ ...ip-permission-adapter-eth-accounts.test.ts | 208 ++++++ .../caip-permission-adapter-eth-accounts.ts | 97 +++ .../caip-permission-adapter-middleware.js | 50 ++ ...caip-permission-adapter-middleware.test.js | 134 ++++ ...permission-adapter-permittedChains.test.ts | 314 ++++++++ ...caip-permission-adapter-permittedChains.ts | 103 +++ .../multichain/src/caip25permissions.test.ts | 688 ++++++++++++++++++ packages/multichain/src/caip25permissions.ts | 251 +++++++ .../src/handlers/wallet-getSession.js | 37 + .../src/handlers/wallet-getSession.test.js | 99 +++ .../src/handlers/wallet-invokeMethod.js | 78 ++ .../src/handlers/wallet-invokeMethod.test.js | 262 +++++++ .../src/handlers/wallet-revokeSession.js | 29 + .../src/handlers/wallet-revokeSession.test.js | 80 ++ packages/multichain/src/index.test.ts | 9 + packages/multichain/src/index.ts | 9 + .../MultichainMiddlewareManager.test.ts | 173 +++++ .../MultichainMiddlewareManager.ts | 123 ++++ .../MultichainSubscriptionManager.test.ts | 124 ++++ .../MultichainSubscriptionManager.ts | 160 ++++ .../multichainMethodCallValidator.ts | 98 +++ packages/multichain/tsconfig.build.json | 10 + packages/multichain/tsconfig.json | 8 + packages/multichain/typedoc.json | 7 + tsconfig.build.json | 1 + tsconfig.json | 1 + yarn.lock | 15 + 33 files changed, 3315 insertions(+), 11 deletions(-) create mode 100644 packages/multichain/CHANGELOG.md create mode 100644 packages/multichain/LICENSE create mode 100644 packages/multichain/README.md create mode 100644 packages/multichain/jest.config.js create mode 100644 packages/multichain/package.json create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.js create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts create mode 100644 packages/multichain/src/caip25permissions.test.ts create mode 100644 packages/multichain/src/caip25permissions.ts create mode 100644 packages/multichain/src/handlers/wallet-getSession.js create mode 100644 packages/multichain/src/handlers/wallet-getSession.test.js create mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.js create mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.test.js create mode 100644 packages/multichain/src/handlers/wallet-revokeSession.js create mode 100644 packages/multichain/src/handlers/wallet-revokeSession.test.js create mode 100644 packages/multichain/src/index.test.ts create mode 100644 packages/multichain/src/index.ts create mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts create mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.ts create mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts create mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.ts create mode 100644 packages/multichain/src/middlewares/multichainMethodCallValidator.ts create mode 100644 packages/multichain/tsconfig.build.json create mode 100644 packages/multichain/tsconfig.json create mode 100644 packages/multichain/typedoc.json diff --git a/README.md b/README.md index e5961edab24..30b0d17682f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ This repository contains the following packages [^fn1]: - [`@metamask/keyring-controller`](packages/keyring-controller) - [`@metamask/logging-controller`](packages/logging-controller) - [`@metamask/message-manager`](packages/message-manager) +- [`@metamask/multichain`](packages/multichain) - [`@metamask/name-controller`](packages/name-controller) - [`@metamask/network-controller`](packages/network-controller) - [`@metamask/notification-controller`](packages/notification-controller) @@ -71,6 +72,7 @@ linkStyle default opacity:0.5 keyring_controller(["@metamask/keyring-controller"]); logging_controller(["@metamask/logging-controller"]); message_manager(["@metamask/message-manager"]); + multichain(["@metamask/multichain"]); name_controller(["@metamask/name-controller"]); network_controller(["@metamask/network-controller"]); notification_controller(["@metamask/notification-controller"]); @@ -93,14 +95,15 @@ linkStyle default opacity:0.5 address_book_controller --> controller_utils; announcement_controller --> base_controller; approval_controller --> base_controller; - assets_controllers --> accounts_controller; - assets_controllers --> approval_controller; assets_controllers --> base_controller; assets_controllers --> controller_utils; + assets_controllers --> polling_controller; + assets_controllers --> accounts_controller; + assets_controllers --> approval_controller; assets_controllers --> keyring_controller; assets_controllers --> network_controller; - assets_controllers --> polling_controller; assets_controllers --> preferences_controller; + base_controller --> json_rpc_engine; chain_controller --> base_controller; composable_controller --> base_controller; composable_controller --> json_rpc_engine; @@ -110,8 +113,8 @@ linkStyle default opacity:0.5 eth_json_rpc_provider --> json_rpc_engine; gas_fee_controller --> base_controller; gas_fee_controller --> controller_utils; - gas_fee_controller --> network_controller; gas_fee_controller --> polling_controller; + gas_fee_controller --> network_controller; json_rpc_middleware_stream --> json_rpc_engine; keyring_controller --> base_controller; keyring_controller --> message_manager; @@ -145,6 +148,9 @@ linkStyle default opacity:0.5 preferences_controller --> controller_utils; preferences_controller --> keyring_controller; profile_sync_controller --> base_controller; + profile_sync_controller --> keyring_controller; + profile_sync_controller --> accounts_controller; + profile_sync_controller --> network_controller; queued_request_controller --> base_controller; queued_request_controller --> controller_utils; queued_request_controller --> json_rpc_engine; @@ -155,26 +161,26 @@ linkStyle default opacity:0.5 selected_network_controller --> json_rpc_engine; selected_network_controller --> network_controller; selected_network_controller --> permission_controller; - signature_controller --> approval_controller; signature_controller --> base_controller; signature_controller --> controller_utils; + signature_controller --> message_manager; + signature_controller --> approval_controller; signature_controller --> keyring_controller; signature_controller --> logging_controller; - signature_controller --> message_manager; - transaction_controller --> accounts_controller; - transaction_controller --> approval_controller; transaction_controller --> base_controller; transaction_controller --> controller_utils; + transaction_controller --> accounts_controller; + transaction_controller --> approval_controller; + transaction_controller --> eth_json_rpc_provider; transaction_controller --> gas_fee_controller; transaction_controller --> network_controller; - transaction_controller --> eth_json_rpc_provider; - user_operation_controller --> approval_controller; user_operation_controller --> base_controller; user_operation_controller --> controller_utils; + user_operation_controller --> polling_controller; + user_operation_controller --> approval_controller; user_operation_controller --> gas_fee_controller; user_operation_controller --> keyring_controller; user_operation_controller --> network_controller; - user_operation_controller --> polling_controller; user_operation_controller --> transaction_controller; ``` diff --git a/packages/multichain/CHANGELOG.md b/packages/multichain/CHANGELOG.md new file mode 100644 index 00000000000..b518709c7b8 --- /dev/null +++ b/packages/multichain/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +[Unreleased]: https://github.com/MetaMask/core/ diff --git a/packages/multichain/LICENSE b/packages/multichain/LICENSE new file mode 100644 index 00000000000..6f8bff03fc4 --- /dev/null +++ b/packages/multichain/LICENSE @@ -0,0 +1,20 @@ +MIT License + +Copyright (c) 2024 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE diff --git a/packages/multichain/README.md b/packages/multichain/README.md new file mode 100644 index 00000000000..dc89e0fade9 --- /dev/null +++ b/packages/multichain/README.md @@ -0,0 +1,15 @@ +# `@metamask/multichain` + +Provides types, helpers, adapters, and wrappers for facilitating CAIP Multichain sessions + +## Installation + +`yarn add @metamask/multichain` + +or + +`npm install @metamask/multichain` + +## Contributing + +This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme). diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js new file mode 100644 index 00000000000..ca084133399 --- /dev/null +++ b/packages/multichain/jest.config.js @@ -0,0 +1,26 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +const merge = require('deepmerge'); +const path = require('path'); + +const baseConfig = require('../../jest.config.packages'); + +const displayName = path.basename(__dirname); + +module.exports = merge(baseConfig, { + // The display name when running multiple projects + displayName, + + // An object that configures minimum threshold enforcement for coverage results + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}); diff --git a/packages/multichain/package.json b/packages/multichain/package.json new file mode 100644 index 00000000000..b7f05dcc3e0 --- /dev/null +++ b/packages/multichain/package.json @@ -0,0 +1,59 @@ +{ + "name": "@metamask/multichain", + "version": "0.0.0", + "description": "Provides types, helpers, adapters, and wrappers for facilitating CAIP Multichain sessions", + "keywords": [ + "MetaMask", + "Ethereum" + ], + "homepage": "https://github.com/MetaMask/core/tree/main/packages/multichain#readme", + "bugs": { + "url": "https://github.com/MetaMask/core/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/core.git" + }, + "license": "MIT", + "sideEffects": false, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js", + "types": "./dist/types/index.d.ts" + }, + "./package.json": "./package.json" + }, + "main": "./dist/index.js", + "types": "./dist/types/index.d.ts", + "files": [ + "dist/" + ], + "scripts": { + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build:docs": "typedoc", + "changelog:validate": "../../scripts/validate-changelog.sh @metamask/multichain", + "publish:preview": "yarn npm publish --tag preview", + "test": "jest --reporters=jest-silent-reporter", + "test:clean": "jest --clearCache", + "test:verbose": "jest --verbose", + "test:watch": "jest --watch" + }, + "devDependencies": { + "@metamask/auto-changelog": "^3.4.4", + "@types/jest": "^27.4.1", + "deepmerge": "^4.2.2", + "jest": "^27.5.1", + "ts-jest": "^27.1.4", + "typedoc": "^0.24.8", + "typedoc-plugin-missing-exports": "^2.0.0", + "typescript": "~5.2.2" + }, + "engines": { + "node": "^18.18 || >=20" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts new file mode 100644 index 00000000000..b7014fe78ee --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -0,0 +1,208 @@ +import { Caip25CaveatValue } from '../caip25permissions'; +import { + getEthAccounts, + setEthAccounts, +} from './caip-permission-adapter-eth-accounts'; + +describe('CAIP-25 eth_accounts adapters', () => { + describe('getEthAccounts', () => { + it('returns the unique set of EIP155 accounts from the CAIP-25 caveat value', () => { + const ethAccounts = getEthAccounts({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0x2', 'eip155:1:0x3'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x4'], + }, + 'eip155:10': { + methods: [], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + accounts: ['wallet:eip155:0x5'], + }, + wallet: { + methods: [], + notifications: [], + accounts: ['wallet:eip155:0x6'], + }, + }, + isMultichainOrigin: false, + }); + + expect(ethAccounts).toStrictEqual([ + '0x1', + '0x2', + '0x4', + '0x3', + '0x100', + '0x5', + '0x6', + ]); + }); + }); + + describe('setEthAccounts', () => { + it('returns a CAIP-25 caveat value with all EIP-155 scopeObject.accounts set to CAIP-10 account addresses formed from the accounts param', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0x2', 'eip155:1:0x3'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x4'], + }, + 'eip155:10': { + methods: [], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, + wallet: { + methods: [], + notifications: [], + }, + }, + isMultichainOrigin: false, + }; + + const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); + expect(result).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2', 'eip155:1:0x3'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0x1', 'eip155:5:0x2', 'eip155:5:0x3'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2', 'eip155:1:0x3'], + }, + 'eip155:10': { + methods: [], + notifications: [], + accounts: ['eip155:10:0x1', 'eip155:10:0x2', 'eip155:10:0x3'], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x1', 'eip155:100:0x2', 'eip155:100:0x3'], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + accounts: [ + 'wallet:eip155:0x1', + 'wallet:eip155:0x2', + 'wallet:eip155:0x3', + ], + }, + wallet: { + methods: [], + notifications: [], + accounts: [ + 'wallet:eip155:0x1', + 'wallet:eip155:0x2', + 'wallet:eip155:0x3', + ], + }, + }, + isMultichainOrigin: false, + }); + }); + + it('does not modify the input CAIP-25 caveat value object in place', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: [], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }; + + const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); + expect(input).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: [], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }); + expect(input).not.toStrictEqual(result); + }); + }); +}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts new file mode 100644 index 00000000000..7f515b5ec28 --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -0,0 +1,97 @@ +import { + CaipAccountId, + Hex, + KnownCaipNamespace, + parseCaipAccountId, +} from '@metamask/utils'; +import { Caip25CaveatValue } from '../caip25permissions'; +import { + mergeScopes, + parseScopeString, + ScopesObject, + ScopeString, +} from '../scope'; + +const isEip155ScopeString = (scopeString: ScopeString) => { + const { namespace, reference } = parseScopeString(scopeString); + + return ( + namespace === KnownCaipNamespace.Eip155 || + (namespace === KnownCaipNamespace.Wallet && + reference === KnownCaipNamespace.Eip155) + ); +}; + +export const getEthAccounts = (caip25CaveatValue: Caip25CaveatValue) => { + const ethAccounts: string[] = []; + const sessionScopes = mergeScopes( + caip25CaveatValue.requiredScopes, + caip25CaveatValue.optionalScopes, + ); + + Object.entries(sessionScopes).forEach(([_, { accounts }]) => { + accounts?.forEach((account) => { + const { address, chainId } = parseCaipAccountId(account); + + if (isEip155ScopeString(chainId)) { + ethAccounts.push(address); + } + }); + }); + + return Array.from(new Set(ethAccounts)); +}; + +const setEthAccountsForScopesObject = ( + scopesObject: ScopesObject, + accounts: Hex[], +) => { + const updatedScopesObject: ScopesObject = {}; + + Object.entries(scopesObject).forEach(([scopeString, scopeObject]) => { + const { namespace, reference } = parseScopeString(scopeString); + + const isWalletNamespace = + namespace === KnownCaipNamespace.Wallet && reference === undefined; + + if ( + !isEip155ScopeString(scopeString as ScopeString) && + !isWalletNamespace + ) { + updatedScopesObject[scopeString as ScopeString] = scopeObject; + return; + } + + const caipAccounts = accounts.map( + (account) => + (isWalletNamespace + ? `wallet:eip155:${account}` + : `${scopeString}:${account}`) as CaipAccountId, + ); + + updatedScopesObject[scopeString as ScopeString] = { + ...scopeObject, + accounts: caipAccounts, + }; + }); + + return updatedScopesObject; +}; + +// This helper must be called with existing eip155 scopes +export const setEthAccounts = ( + caip25CaveatValue: Caip25CaveatValue, + accounts: Hex[], +) => { + return { + ...caip25CaveatValue, + requiredScopes: setEthAccountsForScopesObject( + caip25CaveatValue.requiredScopes, + accounts, + ), + optionalScopes: setEthAccountsForScopesObject( + caip25CaveatValue.optionalScopes, + accounts, + ), + }; +}; diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.js b/packages/multichain/src/adapters/caip-permission-adapter-middleware.js new file mode 100644 index 00000000000..867288eb95a --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.js @@ -0,0 +1,50 @@ +import { providerErrors } from '@metamask/rpc-errors'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25permissions'; +import { mergeScopes } from '../scope'; + +export async function CaipPermissionAdapterMiddleware( + request, + _response, + next, + end, + hooks, +) { + const { networkClientId, method } = request; + + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (err) { + // noop + } + if (!caveat?.value?.isMultichainOrigin) { + return next(); + } + + const { chainId } = + hooks.getNetworkConfigurationByNetworkClientId(networkClientId); + + const scope = `eip155:${parseInt(chainId, 16)}`; + + const scopesObject = mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + ); + + if ( + !scopesObject[scope]?.methods?.includes(method) && + !scopesObject['wallet:eip155']?.methods?.includes(method) && + !scopesObject.wallet?.methods?.includes(method) + ) { + return end(providerErrors.unauthorized()); + } + + return next(); +} diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js new file mode 100644 index 00000000000..f8c0f981371 --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js @@ -0,0 +1,134 @@ +import { providerErrors } from '@metamask/rpc-errors'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25permissions'; +import { CaipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; + +const baseRequest = { + origin: 'http://test.com', + networkClientId: 'mainnet', + method: 'eth_call', + params: { + foo: 'bar', + }, +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + }, + unhandled: { + methods: ['foobar'], + notifications: [], + }, + }, + isMultichainOrigin: true, + }, + }); + const getNetworkConfigurationByNetworkClientId = jest + .fn() + .mockImplementation((networkClientId) => { + const chainId = + { + mainnet: '0x1', + goerli: '0x5', + }[networkClientId] || '0x999'; + return { + chainId, + }; + }); + const handler = (request) => + CaipPermissionAdapterMiddleware(request, {}, next, end, { + getCaveat, + getNetworkConfigurationByNetworkClientId, + }); + + return { + next, + end, + getCaveat, + getNetworkConfigurationByNetworkClientId, + handler, + }; +}; + +describe('CaipPermissionAdapterMiddleware', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const { handler, getCaveat } = createMockedHandler(); + await handler(baseRequest); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('allows the request when there is no CAIP-25 endowment permission', async () => { + const { handler, getCaveat, next } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + + it('allows the request when the CAIP-25 endowment permission was not granted from the multichain API', async () => { + const { handler, getCaveat, next } = createMockedHandler(); + getCaveat.mockReturnValue({ + value: { + isMultichainOrigin: false, + }, + }); + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + + it('gets the chainId for the request networkClientId', async () => { + const { handler, getNetworkConfigurationByNetworkClientId } = + createMockedHandler(); + await handler(baseRequest); + expect(getNetworkConfigurationByNetworkClientId).toHaveBeenCalledWith( + 'mainnet', + ); + }); + + describe('when the CAIP-25 endowment permission was granted over the multichain API', () => { + it('throws an error if the requested method is not authorized for the scope specified in the request', async () => { + const { handler, end } = createMockedHandler(); + + await handler({ + ...baseRequest, + method: 'unauthorized_method', + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('allows the request if the requested scope method is authorized in the current scope', async () => { + const { handler, next } = createMockedHandler(); + + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts new file mode 100644 index 00000000000..aa125193ce9 --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -0,0 +1,314 @@ +import { Caip25CaveatValue } from '../caip25permissions'; +import { KnownNotifications, KnownRpcMethods } from '../scope'; +import { + addPermittedEthChainId, + getPermittedEthChainIds, + setPermittedEthChainIds, +} from './caip-permission-adapter-permittedChains'; + +describe('CAIP-25 permittedChains adapters', () => { + describe('getPermittedEthChainIds', () => { + it('returns the unique set of EIP155 chainIds in hexadecimal format from the CAIP-25 caveat value', () => { + const ethChainIds = getPermittedEthChainIds({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0x2', 'eip155:1:0x3'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x4'], + }, + 'eip155:10': { + methods: [], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }); + + expect(ethChainIds).toStrictEqual(['0x1', '0x5', '0xa', '0x64']); + }); + }); + + describe('addPermittedEthChainId', () => { + it('adds an optional scope for the chainId if it does not already exist in required or optional scopes', () => { + const result = addPermittedEthChainId( + { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }, + '0x65', + ); + + expect(result).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + 'eip155:101': { + methods: KnownRpcMethods.eip155, + notifications: KnownNotifications.eip155, + accounts: [], + }, + }, + isMultichainOrigin: false, + }); + }); + + it('does not modify the input CAIP-25 caveat value object', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }; + + const result = addPermittedEthChainId(input, '0x65'); + + expect(input).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }); + expect(input).not.toStrictEqual(result); + }); + + it('does not add an optional scope for the chainId if already exists in the required scopes', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }; + const result = addPermittedEthChainId(input, '0x1'); + + expect(result).toStrictEqual(input); + }); + + it('does not add an optional scope for the chainId if already exists in the optional scopes', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }; + const result = addPermittedEthChainId(input, '0x64'); // 0x64 === 100 + + expect(result).toStrictEqual(input); + }); + }); + + describe('setPermittedEthChainIds', () => { + it('returns a CAIP-25 caveat value with EIP-155 scopes missing from the chainIds array removed', () => { + const result = setPermittedEthChainIds( + { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }, + ['0x1'], + ); + + expect(result).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'bip122:000000000019d6689c085ae165831e93': { + methods: [], + notifications: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + }, + }, + isMultichainOrigin: false, + }); + }); + + it('returns a CAIP-25 caveat value with optional scopes added for missing chainIds', () => { + const result = setPermittedEthChainIds( + { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }, + ['0x1', '0x64', '0x65'], + ); + + expect(result).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + }, + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + 'eip155:101': { + methods: KnownRpcMethods.eip155, + notifications: KnownNotifications.eip155, + accounts: [], + }, + }, + isMultichainOrigin: false, + }); + }); + + it('does not modify the input CAIP-25 caveat value object', () => { + const input: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }; + + const result = setPermittedEthChainIds(input, ['0x1', '0x2', '0x3']); + + expect(input).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: false, + }); + expect(input).not.toStrictEqual(result); + }); + }); +}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts new file mode 100644 index 00000000000..8e840c6c327 --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -0,0 +1,103 @@ +import { Hex, KnownCaipNamespace } from '@metamask/utils'; +import { toHex } from '@metamask/controller-utils'; +import { Caip25CaveatValue } from '../caip25permissions'; +import { + KnownNotifications, + KnownRpcMethods, + mergeScopes, + parseScopeString, + ScopesObject, + ScopeString, +} from '../scope'; + +export const getPermittedEthChainIds = ( + caip25CaveatValue: Caip25CaveatValue, +) => { + const ethChainIds: Hex[] = []; + const sessionScopes = mergeScopes( + caip25CaveatValue.requiredScopes, + caip25CaveatValue.optionalScopes, + ); + + Object.keys(sessionScopes).forEach((scopeString) => { + const { namespace, reference } = parseScopeString(scopeString); + if (namespace === KnownCaipNamespace.Eip155 && reference) { + ethChainIds.push(toHex(reference)); + } + }); + + return Array.from(new Set(ethChainIds)); +}; + +export const addPermittedEthChainId = ( + caip25CaveatValue: Caip25CaveatValue, + chainId: Hex, +) => { + const scopeString = `eip155:${parseInt(chainId, 16)}`; + if ( + Object.keys(caip25CaveatValue.requiredScopes).includes(scopeString) || + Object.keys(caip25CaveatValue.optionalScopes).includes(scopeString) + ) { + return caip25CaveatValue; + } + + return { + ...caip25CaveatValue, + optionalScopes: { + ...caip25CaveatValue.optionalScopes, + [scopeString]: { + methods: KnownRpcMethods.eip155, + notifications: KnownNotifications.eip155, + accounts: [], + }, + }, + }; +}; + +const filterEthScopesObjectByChainId = ( + scopesObject: ScopesObject, + chainIds: Hex[], +) => { + const updatedScopesObject: ScopesObject = {}; + + Object.entries(scopesObject).forEach(([scopeString, scopeObject]) => { + const { namespace, reference } = parseScopeString(scopeString); + if (!reference) { + updatedScopesObject[scopeString as ScopeString] = scopeObject; + return; + } + if (namespace === KnownCaipNamespace.Eip155) { + const chainId = toHex(reference); + if (chainIds.includes(chainId)) { + updatedScopesObject[scopeString as ScopeString] = scopeObject; + } + } else { + updatedScopesObject[scopeString as ScopeString] = scopeObject; + } + }); + + return updatedScopesObject; +}; + +export const setPermittedEthChainIds = ( + caip25CaveatValue: Caip25CaveatValue, + chainIds: Hex[], +) => { + let updatedCaveatValue: Caip25CaveatValue = { + ...caip25CaveatValue, + requiredScopes: filterEthScopesObjectByChainId( + caip25CaveatValue.requiredScopes, + chainIds, + ), + optionalScopes: filterEthScopesObjectByChainId( + caip25CaveatValue.optionalScopes, + chainIds, + ), + }; + + chainIds.forEach((chainId) => { + updatedCaveatValue = addPermittedEthChainId(updatedCaveatValue, chainId); + }); + + return updatedCaveatValue; +}; diff --git a/packages/multichain/src/caip25permissions.test.ts b/packages/multichain/src/caip25permissions.test.ts new file mode 100644 index 00000000000..97fce8f631d --- /dev/null +++ b/packages/multichain/src/caip25permissions.test.ts @@ -0,0 +1,688 @@ +import { + CaveatConstraint, + CaveatMutatorOperation, + PermissionType, + SubjectType, +} from '@metamask/permission-controller'; +import { NonEmptyArray } from '@metamask/controller-utils'; +import * as Scope from './scope'; +import { + Caip25CaveatType, + Caip25CaveatValue, + caip25EndowmentBuilder, + Caip25EndowmentPermissionName, + Caip25CaveatMutatorFactories, + removeScope, +} from './caip25permissions'; + +jest.mock('./scope', () => ({ + validateAndFlattenScopes: jest.fn(), + assertScopesSupported: jest.fn(), +})); +const MockScope = jest.mocked(Scope); + +const { removeAccount } = Caip25CaveatMutatorFactories[Caip25CaveatType]; + +describe('endowment:caip25', () => { + beforeEach(() => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: {}, + flattenedOptionalScopes: {}, + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('builds the expected permission specification', () => { + const specification = caip25EndowmentBuilder.specificationBuilder({ + methodHooks: { + findNetworkClientIdByChainId: jest.fn(), + }, + }); + expect(specification).toStrictEqual({ + permissionType: PermissionType.Endowment, + targetName: Caip25EndowmentPermissionName, + endowmentGetter: expect.any(Function), + allowedCaveats: [Caip25CaveatType], + subjectTypes: [SubjectType.Website], + validator: expect.any(Function), + }); + + expect(specification.endowmentGetter()).toBeNull(); + }); + + describe('caveat mutator removeScope', () => { + it('can remove a caveat', () => { + const ethereumGoerliCaveat = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: ['eth_call'], + notifications: ['accountsChanged'], + }, + }, + sessionProperties: {}, + isMultichainOrigin: true, + }; + const result = removeScope('eip155:5', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.updateValue, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + }, + }, + optionalScopes: {}, + }, + }); + }); + + it('can revoke the entire permission when a requiredScope is removed', () => { + const ethereumGoerliCaveat = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: ['eth_call'], + notifications: ['accountsChanged'], + }, + }, + sessionProperties: {}, + isMultichainOrigin: true, + }; + const result = removeScope('eip155:1', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.revokePermission, + }); + }); + + it('can noop when nothing is removed', () => { + const ethereumGoerliCaveat = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: ['eth_call'], + notifications: ['accountsChanged'], + }, + }, + sessionProperties: {}, + isMultichainOrigin: true, + }; + const result = removeScope('eip155:2', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.noop, + }); + }); + }); + + describe('caveat mutator removeAccount', () => { + it('can remove an account', () => { + const ethereumGoerliCaveat: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: true, + }; + const result = removeAccount('0x1', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.updateValue, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0x2'], + }, + }, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }); + }); + + it('can remove an account in multiple scopes in optional and required', () => { + const ethereumGoerliCaveat: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + 'eip155:2': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:2:0x1', 'eip155:2:0x2'], + }, + }, + optionalScopes: { + 'eip155:3': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:3:0x1', 'eip155:3:0x2'], + }, + }, + isMultichainOrigin: true, + }; + const result = removeAccount('0x1', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.updateValue, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0x2'], + }, + 'eip155:2': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:2:0x2'], + }, + }, + optionalScopes: { + 'eip155:3': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:3:0x2'], + }, + }, + isMultichainOrigin: true, + }, + }); + }); + + it('can noop when nothing is removed', () => { + const ethereumGoerliCaveat: Caip25CaveatValue = { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: ['eth_call'], + notifications: ['accountsChanged'], + }, + }, + isMultichainOrigin: true, + }; + const result = removeAccount('0x3', ethereumGoerliCaveat); + expect(result).toStrictEqual({ + operation: CaveatMutatorOperation.noop, + }); + }); + }); + + describe('permission validator', () => { + const findNetworkClientIdByChainId = jest.fn(); + const { validator } = caip25EndowmentBuilder.specificationBuilder({ + findNetworkClientIdByChainId, + }); + + it('throws an error if there is not exactly one caveat', () => { + expect(() => { + validator({ + caveats: [ + { + type: 'caveatType', + value: {}, + }, + { + type: 'caveatType', + value: {}, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Invalid caveats. There must be a single caveat of type "${Caip25CaveatType}".`, + ), + ); + + expect(() => { + validator({ + caveats: [] as unknown as NonEmptyArray, + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Invalid caveats. There must be a single caveat of type "${Caip25CaveatType}".`, + ), + ); + }); + + it('throws an error if there is no CAIP-25 caveat', () => { + expect(() => { + validator({ + caveats: [ + { + type: 'NotCaip25Caveat', + value: {}, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Invalid caveats. There must be a single caveat of type "${Caip25CaveatType}".`, + ), + ); + }); + + it('throws an error if the CAIP-25 caveat is malformed', () => { + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + missingRequiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Received invalid value for caveat of type "${Caip25CaveatType}".`, + ), + ); + + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + missingOptionalScopes: {}, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Received invalid value for caveat of type "${Caip25CaveatType}".`, + ), + ); + + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: 'NotABoolean', + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Received invalid value for caveat of type "${Caip25CaveatType}".`, + ), + ); + }); + + it('validates and flattens the ScopesObjects', () => { + try { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + } catch (err) { + // noop + } + expect(MockScope.validateAndFlattenScopes).toHaveBeenCalledWith( + { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + ); + }); + + it('asserts the validated and flattened required scopes are supported', () => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: { + 'eip155:1': { + methods: ['flattened_required'], + notifications: [], + }, + }, + flattenedOptionalScopes: { + 'eip155:1': { + methods: ['flattened_optional'], + notifications: [], + }, + }, + }); + try { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + } catch (err) { + // noop + } + expect(MockScope.assertScopesSupported).toHaveBeenCalledWith( + { + 'eip155:1': { + methods: ['flattened_required'], + notifications: [], + }, + }, + expect.objectContaining({ + isChainIdSupported: expect.any(Function), + }), + ); + const isChainIdSupportedBody = + MockScope.assertScopesSupported.mock.calls[0][1].isChainIdSupported.toString(); + expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + }); + + it('asserts the validated and flattened optional scopes are supported', () => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: { + 'eip155:1': { + methods: ['flattened_required'], + notifications: [], + }, + }, + flattenedOptionalScopes: { + 'eip155:1': { + methods: ['flattened_optional'], + notifications: [], + }, + }, + }); + try { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + } catch (err) { + // noop + } + expect(MockScope.assertScopesSupported).toHaveBeenCalledWith( + { + 'eip155:1': { + methods: ['flattened_optional'], + notifications: [], + }, + }, + expect.objectContaining({ + isChainIdSupported: expect.any(Function), + }), + ); + const isChainIdSupportedBody = + MockScope.assertScopesSupported.mock.calls[1][1].isChainIdSupported.toString(); + expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + }); + + it('throws if the input requiredScopes does not match the output of validateAndFlattenScopes', () => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: {}, + flattenedOptionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + }); + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow(/Expected values to be strictly deep-equal/u); + }); + + it('throws if the input optionalScopes does not match the output of validateAndFlattenScopes', () => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + flattenedOptionalScopes: {}, + }); + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow(/Expected values to be strictly deep-equal/u); + }); + + it('does not throw if the input requiredScopes and optionalScopes ScopesObject are already validated and flattened', () => { + MockScope.validateAndFlattenScopes.mockReturnValue({ + flattenedRequiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + flattenedOptionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + }); + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }); + }); +}); diff --git a/packages/multichain/src/caip25permissions.ts b/packages/multichain/src/caip25permissions.ts new file mode 100644 index 00000000000..335f17113a2 --- /dev/null +++ b/packages/multichain/src/caip25permissions.ts @@ -0,0 +1,251 @@ +import { strict as assert } from 'assert'; +import type { + PermissionSpecificationBuilder, + EndowmentGetterParams, + ValidPermissionSpecification, + PermissionValidatorConstraint, + PermissionConstraint, +} from '@metamask/permission-controller'; +import { + CaveatMutatorOperation, + PermissionType, + SubjectType, +} from '@metamask/permission-controller'; +import { + CaipAccountId, + Json, + parseCaipAccountId, + type Hex, + type NonEmptyArray, +} from '@metamask/utils'; +import { NetworkClientId } from '@metamask/network-controller'; +import { cloneDeep, isEqual } from 'lodash'; +import { + ExternalScopeString, + validateAndFlattenScopes, + ScopesObject, + ScopeObject, + assertScopesSupported, +} from './scope'; + +export type Caip25CaveatValue = { + requiredScopes: ScopesObject; + optionalScopes: ScopesObject; + sessionProperties?: Record; + isMultichainOrigin: boolean; +}; + +export const Caip25CaveatType = 'authorizedScopes'; + +export const Caip25CaveatFactoryFn = (value: Caip25CaveatValue) => { + return { + type: Caip25CaveatType, + value, + }; +}; + +export const Caip25EndowmentPermissionName = 'endowment:caip25'; + +type Caip25EndowmentSpecification = ValidPermissionSpecification<{ + permissionType: PermissionType.Endowment; + targetName: typeof Caip25EndowmentPermissionName; + endowmentGetter: (_options?: EndowmentGetterParams) => null; + validator: PermissionValidatorConstraint; + allowedCaveats: Readonly> | null; +}>; + +/** + * `endowment:caip25` returns nothing atm; + * + * @param builderOptions - The specification builder options. + * @param builderOptions.findNetworkClientIdByChainId + * @returns The specification for the `caip25` endowment. + */ +const specificationBuilder: PermissionSpecificationBuilder< + PermissionType.Endowment, + // TODO: FIX THIS + // eslint-disable-next-line @typescript-eslint/no-explicit-any + any, + Caip25EndowmentSpecification +> = ({ + findNetworkClientIdByChainId, +}: { + findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId; +}) => { + return { + permissionType: PermissionType.Endowment, + targetName: Caip25EndowmentPermissionName, + allowedCaveats: [Caip25CaveatType], + endowmentGetter: (_getterOptions?: EndowmentGetterParams) => null, + subjectTypes: [SubjectType.Website], + validator: (permission: PermissionConstraint) => { + const caip25Caveat = permission.caveats?.[0]; + if ( + permission.caveats?.length !== 1 || + caip25Caveat?.type !== Caip25CaveatType + ) { + throw new Error( + `${Caip25EndowmentPermissionName} error: Invalid caveats. There must be a single caveat of type "${Caip25CaveatType}".`, + ); + } + + // TODO: FIX THIS TYPE + const { requiredScopes, optionalScopes, isMultichainOrigin } = ( + caip25Caveat as unknown as { value: Caip25CaveatValue } + ).value; + + if ( + !requiredScopes || + !optionalScopes || + typeof isMultichainOrigin !== 'boolean' + ) { + throw new Error( + `${Caip25EndowmentPermissionName} error: Received invalid value for caveat of type "${Caip25CaveatType}".`, + ); + } + + const { flattenedRequiredScopes, flattenedOptionalScopes } = + validateAndFlattenScopes(requiredScopes, optionalScopes); + + const isChainIdSupported = (chainId: Hex) => { + try { + findNetworkClientIdByChainId(chainId); + return true; + } catch (err) { + return false; + } + }; + + assertScopesSupported(flattenedRequiredScopes, { + isChainIdSupported, + }); + assertScopesSupported(flattenedOptionalScopes, { + isChainIdSupported, + }); + + assert.deepEqual(requiredScopes, flattenedRequiredScopes); + assert.deepEqual(optionalScopes, flattenedOptionalScopes); + }, + }; +}; + +export const caip25EndowmentBuilder = Object.freeze({ + targetName: Caip25EndowmentPermissionName, + specificationBuilder, +} as const); + +/** + * Factories that construct caveat mutator functions that are passed to + * PermissionController.updatePermissionsByCaveat. + */ +export const Caip25CaveatMutatorFactories = { + [Caip25CaveatType]: { + removeScope, + removeAccount, + }, +}; + +const reduceKeysHelper = ( + acc: Record, + [key, value]: [K, V], +) => { + return { + ...acc, + [key]: value, + }; +}; + +function removeAccountFilterFn(targetAddress: string) { + return (account: CaipAccountId) => { + const parsed = parseCaipAccountId(account); + return parsed.address !== targetAddress; + }; +} + +function removeAccountOnScope(targetAddress: string, scopeObject: ScopeObject) { + if (scopeObject.accounts) { + scopeObject.accounts = scopeObject.accounts.filter( + removeAccountFilterFn(targetAddress), + ); + } +} + +function removeAccount( + targetAddress: string, // non caip-10 formatted address + existingScopes: Caip25CaveatValue, +) { + // copy existing scopes + const copyOfExistingScopes = cloneDeep(existingScopes); + + [ + copyOfExistingScopes.requiredScopes, + copyOfExistingScopes.optionalScopes, + ].forEach((scopes) => { + Object.entries(scopes).forEach(([, scopeObject]) => { + removeAccountOnScope(targetAddress, scopeObject); + }); + }); + + // deep equal check for changes + const noChange = isEqual(copyOfExistingScopes, existingScopes); + + if (noChange) { + return { + operation: CaveatMutatorOperation.noop, + }; + } + + return { + operation: CaveatMutatorOperation.updateValue, + value: copyOfExistingScopes, + }; +} + +/** + * Removes the target account from the value arrays of all + * `endowment:caip25` caveats. No-ops if the target scopeString is not in + * the existing scopes,. + * + * @param targetScopeString - The scope that is being removed. + * @param caip25CaveatValue - The CAIP-25 permission caveat value to remove the scope from. + */ +export function removeScope( + targetScopeString: ExternalScopeString, + caip25CaveatValue: Caip25CaveatValue, +) { + const newRequiredScopes = Object.entries( + caip25CaveatValue.requiredScopes, + ).filter(([scope]) => scope !== targetScopeString); + const newOptionalScopes = Object.entries( + caip25CaveatValue.optionalScopes, + ).filter(([scope]) => { + return scope !== targetScopeString; + }); + + const requiredScopesRemoved = + newRequiredScopes.length !== + Object.keys(caip25CaveatValue.requiredScopes).length; + const optionalScopesRemoved = + newOptionalScopes.length !== + Object.keys(caip25CaveatValue.optionalScopes).length; + + if (requiredScopesRemoved) { + return { + operation: CaveatMutatorOperation.revokePermission, + }; + } + + if (optionalScopesRemoved) { + return { + operation: CaveatMutatorOperation.updateValue, + value: { + requiredScopes: newRequiredScopes.reduce(reduceKeysHelper, {}), + optionalScopes: newOptionalScopes.reduce(reduceKeysHelper, {}), + }, + }; + } + + return { + operation: CaveatMutatorOperation.noop, + }; +} diff --git a/packages/multichain/src/handlers/wallet-getSession.js b/packages/multichain/src/handlers/wallet-getSession.js new file mode 100644 index 00000000000..e10e2781250 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-getSession.js @@ -0,0 +1,37 @@ +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25permissions'; +import { mergeScopes } from './scope'; + +export async function walletGetSessionHandler( + request, + response, + _next, + end, + hooks, +) { + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (e) { + // noop + } + + if (!caveat) { + response.result = { sessionScopes: {} }; + return end(); + } + + response.result = { + sessionScopes: mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + ), + }; + return end(); +} diff --git a/packages/multichain/src/handlers/wallet-getSession.test.js b/packages/multichain/src/handlers/wallet-getSession.test.js new file mode 100644 index 00000000000..de51365869c --- /dev/null +++ b/packages/multichain/src/handlers/wallet-getSession.test.js @@ -0,0 +1,99 @@ +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25permissions'; +import { walletGetSessionHandler } from './wallet-getSession'; + +const baseRequest = { + origin: 'http://test.com', + params: {}, +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: ['chainChanged'], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + }, + }, + }, + }); + const response = {}; + const handler = (request) => + walletGetSessionHandler(request, response, next, end, { + getCaveat, + }); + + return { + next, + response, + end, + getCaveat, + handler, + }; +}; + +describe('wallet_getSession', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const { handler, getCaveat } = createMockedHandler(); + + await handler(baseRequest); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('returns empty scopes if the CAIP-25 endowment permission does not exist', async () => { + const { handler, response, getCaveat } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + + await handler(baseRequest); + expect(response.result).toStrictEqual({ + sessionScopes: {}, + }); + }); + + it('returns the merged scopes', async () => { + const { handler, response } = createMockedHandler(); + + await handler(baseRequest); + expect(response.result).toStrictEqual({ + sessionScopes: { + 'eip155:1': { + methods: ['eth_call', 'net_version'], + notifications: ['chainChanged'], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + }, + }, + }); + }); +}); diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.js b/packages/multichain/src/handlers/wallet-invokeMethod.js new file mode 100644 index 00000000000..14b20437264 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-invokeMethod.js @@ -0,0 +1,78 @@ +import { numberToHex } from '@metamask/utils'; +import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from './caip25permissions'; +import { mergeScopes, parseScopeString } from './scope'; + +export async function walletInvokeMethodHandler( + request, + _response, + next, + end, + hooks, +) { + const { scope, request: wrappedRequest } = request.params; + + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (e) { + // noop + } + if (!caveat?.value?.isMultichainOrigin) { + return end(providerErrors.unauthorized()); + } + + const scopeObject = mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + )[scope]; + + if (!scopeObject?.methods?.includes(wrappedRequest.method)) { + return end(providerErrors.unauthorized()); + } + + const { namespace, reference } = parseScopeString(scope); + + let networkClientId; + switch (namespace) { + case 'wallet': + networkClientId = hooks.getSelectedNetworkClientId(); + break; + case 'eip155': + if (reference) { + networkClientId = hooks.findNetworkClientIdByChainId( + numberToHex(parseInt(reference, 10)), + ); + } + break; + default: + console.error( + 'failed to resolve namespace for wallet_invokeMethod', + request, + ); + return end(rpcErrors.internal()); + } + + if (!networkClientId) { + console.error( + 'failed to resolve network client for wallet_invokeMethod', + request, + ); + return end(rpcErrors.internal()); + } + + Object.assign(request, { + scope, + networkClientId, + method: wrappedRequest.method, + params: wrappedRequest.params, + }); + return next(); +} diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.js b/packages/multichain/src/handlers/wallet-invokeMethod.test.js new file mode 100644 index 00000000000..dcf0d5f4ac8 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.js @@ -0,0 +1,262 @@ +import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from './caip25permissions'; +import { walletInvokeMethodHandler } from './wallet-invokeMethod'; + +const createMockedRequest = () => ({ + origin: 'http://test.com', + params: { + scope: 'eip155:1', + request: { + method: 'eth_call', + params: { + foo: 'bar', + }, + }, + }, +}); + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + }, + unhandled: { + methods: ['foobar'], + notifications: [], + }, + }, + isMultichainOrigin: true, + }, + }); + const findNetworkClientIdByChainId = jest.fn().mockReturnValue('mainnet'); + const getSelectedNetworkClientId = jest + .fn() + .mockReturnValue('selectedNetworkClientId'); + const handler = (request) => + walletInvokeMethodHandler(request, {}, next, end, { + getCaveat, + findNetworkClientIdByChainId, + getSelectedNetworkClientId, + }); + + return { + next, + end, + getCaveat, + findNetworkClientIdByChainId, + getSelectedNetworkClientId, + handler, + }; +}; + +describe('wallet_invokeMethod', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const request = createMockedRequest(); + const { handler, getCaveat } = createMockedHandler(); + await handler(request); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('throws an unauthorized error when there is no CAIP-25 endowment permission', async () => { + const request = createMockedRequest(); + const { handler, getCaveat, end } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + await handler(request); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error when the CAIP-25 endowment permission was not granted from the multichain flow', async () => { + const request = createMockedRequest(); + const { handler, getCaveat, end } = createMockedHandler(); + getCaveat.mockReturnValue({ + value: { + isMultichainOrigin: false, + }, + }); + await handler(request); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error if the requested scope is not authorized', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'eip155:999', + }, + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error if the requested scope method is not authorized', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + request: { + ...request.params.request, + method: 'unauthorized_method', + }, + }, + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an internal error for authorized but unhandled scopes', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'unhandled', + request: { + ...request.params.request, + method: 'foobar', + }, + }, + }); + + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + describe('ethereum scope', () => { + it('gets the networkClientId for the chainId', async () => { + const request = createMockedRequest(); + const { handler, findNetworkClientIdByChainId } = createMockedHandler(); + + await handler(request); + expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); + }); + + it('throws an internal error if a networkClientId does not exist for the chainId', async () => { + const request = createMockedRequest(); + const { handler, findNetworkClientIdByChainId, end } = + createMockedHandler(); + findNetworkClientIdByChainId.mockReturnValue(undefined); + + await handler(request); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('sets the networkClientId and unwraps the CAIP-27 request', async () => { + const request = createMockedRequest(); + const { handler, next } = createMockedHandler(); + + await handler(request); + expect(request).toStrictEqual({ + scope: 'eip155:1', + origin: 'http://test.com', + networkClientId: 'mainnet', + method: 'eth_call', + params: { + foo: 'bar', + }, + }); + expect(next).toHaveBeenCalled(); + }); + }); + + describe('wallet scope', () => { + it('gets the networkClientId for the globally selected network', async () => { + const request = createMockedRequest(); + const { handler, getSelectedNetworkClientId } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }); + expect(getSelectedNetworkClientId).toHaveBeenCalled(); + }); + + it('throws an internal error if a networkClientId cannot be retrieved for the globally selected network', async () => { + const request = createMockedRequest(); + const { handler, getSelectedNetworkClientId, end } = + createMockedHandler(); + getSelectedNetworkClientId.mockReturnValue(undefined); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('sets the networkClientId and unwraps the CAIP-27 request', async () => { + const request = createMockedRequest(); + const { handler, next } = createMockedHandler(); + + const walletRequest = { + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }; + await handler(walletRequest); + expect(walletRequest).toStrictEqual({ + scope: 'wallet', + origin: 'http://test.com', + networkClientId: 'selectedNetworkClientId', + method: 'wallet_watchAsset', + params: { + foo: 'bar', + }, + }); + expect(next).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.js b/packages/multichain/src/handlers/wallet-revokeSession.js new file mode 100644 index 00000000000..e0425cf3260 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-revokeSession.js @@ -0,0 +1,29 @@ +import { + PermissionDoesNotExistError, + UnrecognizedSubjectError, +} from '@metamask/permission-controller'; +import { rpcErrors } from '@metamask/rpc-errors'; +import { Caip25EndowmentPermissionName } from '../caip25permissions'; + +export async function walletRevokeSessionHandler( + request, + response, + _next, + end, + hooks, +) { + try { + hooks.revokePermission(request.origin, Caip25EndowmentPermissionName); + } catch (err) { + if ( + !(err instanceof UnrecognizedSubjectError) && + !(err instanceof PermissionDoesNotExistError) + ) { + console.error(err); + return end(rpcErrors.internal()); + } + } + + response.result = true; + return end(); +} diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.js b/packages/multichain/src/handlers/wallet-revokeSession.test.js new file mode 100644 index 00000000000..8acd84ac3dc --- /dev/null +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.js @@ -0,0 +1,80 @@ +import { + PermissionDoesNotExistError, + UnrecognizedSubjectError, +} from '@metamask/permission-controller'; +import { rpcErrors } from '@metamask/rpc-errors'; +import { Caip25EndowmentPermissionName } from '../caip25permissions'; +import { walletRevokeSessionHandler } from './wallet-revokeSession'; + +const baseRequest = { + origin: 'http://test.com', + params: {}, +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const revokePermission = jest.fn(); + const response = {}; + const handler = (request) => + walletRevokeSessionHandler(request, response, next, end, { + revokePermission, + }); + + return { + next, + response, + end, + revokePermission, + handler, + }; +}; + +describe('wallet_revokeSession', () => { + it('revokes the the CAIP-25 endowment permission', async () => { + const { handler, revokePermission } = createMockedHandler(); + + await handler(baseRequest); + expect(revokePermission).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + ); + }); + + it('returns true if the CAIP-25 endowment permission does not exist', async () => { + const { handler, response, revokePermission } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new PermissionDoesNotExistError(); + }); + + await handler(baseRequest); + expect(response.result).toStrictEqual(true); + }); + + it('returns true if the subject does not exist', async () => { + const { handler, response, revokePermission } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new UnrecognizedSubjectError(); + }); + + await handler(baseRequest); + expect(response.result).toStrictEqual(true); + }); + + it('throws an internal RPC error if something unexpected goes wrong with revoking the permission', async () => { + const { handler, revokePermission, end } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new Error('revoke failed'); + }); + + await handler(baseRequest); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('returns true if the permission was revoked', async () => { + const { handler, response } = createMockedHandler(); + + await handler(baseRequest); + expect(response.result).toStrictEqual(true); + }); +}); diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts new file mode 100644 index 00000000000..bc062d3694a --- /dev/null +++ b/packages/multichain/src/index.test.ts @@ -0,0 +1,9 @@ +import greeter from '.'; + +describe('Test', () => { + it('greets', () => { + const name = 'Huey'; + const result = greeter(name); + expect(result).toBe('Hello, Huey!'); + }); +}); diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts new file mode 100644 index 00000000000..6972c117292 --- /dev/null +++ b/packages/multichain/src/index.ts @@ -0,0 +1,9 @@ +/** + * Example function that returns a greeting for the given name. + * + * @param name - The name to greet. + * @returns The greeting. + */ +export default function greeter(name: string): string { + return `Hello, ${name}!`; +} diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts new file mode 100644 index 00000000000..099e09537e4 --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -0,0 +1,173 @@ +import { JsonRpcRequest } from 'json-rpc-engine'; +import MultichainMiddlewareManager, { + ExtendedJsonRpcMiddleware, +} from './MultichainMiddlewareManager'; + +const scope = 'eip155:1'; +const origin = 'example.com'; +const tabId = 123; + +describe('MultichainMiddlewareManager', () => { + it('should add middleware and get called for the scope, origin, and tabId', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).toHaveBeenCalledWith( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + middleware.destroy?.(); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by scope', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByScope(scope); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by scope and origin', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByScopeAndOrigin(scope, origin); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by origin and tabId', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByOriginAndTabId(origin, tabId); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts new file mode 100644 index 00000000000..f0b52b655ef --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -0,0 +1,123 @@ +import { JsonRpcMiddleware } from 'json-rpc-engine'; +import { ExternalScopeString } from './scope'; + +// Extend JsonRpcMiddleware to include the destroy method +// this was introduced in 7.0.0 of json-rpc-engine: https://github.com/MetaMask/json-rpc-engine/blob/v7.0.0/src/JsonRpcEngine.ts#L29-L40 +export type ExtendedJsonRpcMiddleware = JsonRpcMiddleware & { + destroy?: () => void; +}; + +type MiddlewareKey = { + scope: ExternalScopeString; + origin: string; + tabId?: number; +}; +type MiddlewareEntry = MiddlewareKey & { + middleware: ExtendedJsonRpcMiddleware; +}; + +export default class MultichainMiddlewareManager { + #middlewares: MiddlewareEntry[] = []; + + #getMiddlewareEntry({ + scope, + origin, + tabId, + }: MiddlewareKey): MiddlewareEntry | undefined { + return this.#middlewares.find((middlewareEntry) => { + return ( + middlewareEntry.scope === scope && + middlewareEntry.origin === origin && + middlewareEntry.tabId === tabId + ); + }); + } + + #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareKey) { + this.#middlewares = this.#middlewares.filter((middlewareEntry) => { + return ( + middlewareEntry.scope !== scope || + middlewareEntry.origin !== origin || + middlewareEntry.tabId !== tabId + ); + }); + } + + addMiddleware(middlewareEntry: MiddlewareEntry) { + const { scope, origin, tabId } = middlewareEntry; + if (!this.#getMiddlewareEntry({ scope, origin, tabId })) { + this.#middlewares.push(middlewareEntry); + } + } + + #removeMiddleware(middlewareKey: MiddlewareKey) { + const existingMiddlewareEntry = this.#getMiddlewareEntry(middlewareKey); + if (!existingMiddlewareEntry) { + return; + } + + existingMiddlewareEntry.middleware.destroy?.(); + + this.#removeMiddlewareEntry(middlewareKey); + } + + removeMiddlewareByScope(scope: ExternalScopeString) { + this.#middlewares.forEach((middlewareEntry) => { + if (middlewareEntry.scope === scope) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) { + this.#middlewares.forEach((middlewareEntry) => { + if ( + middlewareEntry.scope === scope && + middlewareEntry.origin === origin + ) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) { + this.#middlewares.forEach((middlewareEntry) => { + if ( + middlewareEntry.origin === origin && + middlewareEntry.tabId === tabId + ) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + generateMultichainMiddlewareForOriginAndTabId( + origin: string, + tabId?: number, + ) { + const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => { + const r = req as unknown as { + scope: string; + }; + const { scope } = r; + const middlewareEntry = this.#getMiddlewareEntry({ + scope, + origin, + tabId, + }); + + if (middlewareEntry) { + middlewareEntry.middleware(req, res, next, end); + } else { + next(); + } + }; + middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind( + this, + origin, + tabId, + ); + + return middleware; + } +} diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts new file mode 100644 index 00000000000..f5e3c0147cd --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -0,0 +1,124 @@ +import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; +import MultichainSubscriptionManager from './MultichainSubscriptionManager'; + +jest.mock('@metamask/eth-json-rpc-filters/subscriptionManager', () => + jest.fn(), +); +const MockCreateSubscriptionManager = jest.mocked(createSubscriptionManager); + +const newHeadsNotificationMock = { + method: 'eth_subscription', + params: { + result: { + difficulty: '0x15d9223a23aa', + extraData: '0xd983010305844765746887676f312e342e328777696e646f7773', + gasLimit: '0x47e7c4', + gasUsed: '0x38658', + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + miner: '0xf8b483dba2c3b7176a3da549ad41a48bb3121069', + nonce: '0x084149998194cc5f', + number: '0x1348c9', + parentHash: + '0x7736fab79e05dc611604d22470dadad26f56fe494421b5b333de816ce1f25701', + receiptRoot: + '0x2fab35823ad00c7bb388595cb46652fe7886e00660a01e867824d3dceb1c8d36', + sha3Uncles: + '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + stateRoot: + '0xb3346685172db67de536d8765c43c31009d0eb3bd9c501c9be3229203f15f378', + timestamp: '0x56ffeff8', + }, + }, +}; + +const scope = 'eip155:1'; +const origin = 'example.com'; +const tabId = 123; + +const createMultichainSubscriptionManager = () => { + const mockFindNetworkClientIdByChainId = jest.fn(); + const mockGetNetworkClientById = jest.fn().mockImplementation(() => ({ + blockTracker: {}, + provider: {}, + })); + const multichainSubscriptionManager = new MultichainSubscriptionManager({ + findNetworkClientIdByChainId: mockFindNetworkClientIdByChainId, + getNetworkClientById: mockGetNetworkClientById, + }); + const onNotificationSpy = jest.fn(); + + multichainSubscriptionManager.on('notification', onNotificationSpy); + + return { multichainSubscriptionManager, onNotificationSpy }; +}; + +describe('MultichainSubscriptionManager', () => { + const mockSubscriptionManager = { + events: { + on: jest.fn(), + }, + destroy: jest.fn(), + }; + + beforeEach(() => { + MockCreateSubscriptionManager.mockReturnValue(mockSubscriptionManager); + }); + + it('should subscribe to a scope, origin, and tabId', () => { + const { multichainSubscriptionManager, onNotificationSpy } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(onNotificationSpy).toHaveBeenCalledWith(origin, tabId, { + method: 'wallet_notify', + params: { + scope, + notification: newHeadsNotificationMock, + }, + }); + }); + + it('should unsubscribe from a scope', () => { + const { multichainSubscriptionManager, onNotificationSpy } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByScope(scope); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(onNotificationSpy).not.toHaveBeenCalled(); + }); + + it('should unsubscribe from a scope and origin', () => { + const { multichainSubscriptionManager, onNotificationSpy } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(onNotificationSpy).not.toHaveBeenCalled(); + }); + + it('should unsubscribe from a origin and tabId', () => { + const { multichainSubscriptionManager, onNotificationSpy } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(onNotificationSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts new file mode 100644 index 00000000000..5cf94f05979 --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -0,0 +1,160 @@ +import EventEmitter from 'events'; +import { NetworkController } from '@metamask/network-controller'; +import SafeEventEmitter from '@metamask/safe-event-emitter'; +import { Hex, parseCaipChainId } from '@metamask/utils'; +import { toHex } from '@metamask/controller-utils'; +import { ExternalScopeString, ScopeString } from './scope'; + +export type SubscriptionManager = { + events: EventEmitter; + destroy?: () => void; +}; + +type SubscriptionNotificationEvent = { + jsonrpc: '2.0'; + method: 'eth_subscription'; + params: { + subscription: Hex; + result: unknown; + }; +}; + +type SubscriptionKey = { + scope: ExternalScopeString; + origin: string; + tabId?: number; +}; +type SubscriptionEntry = SubscriptionKey & { + subscriptionManager: SubscriptionManager; +}; + +// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires +const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); + +type MultichainSubscriptionManagerOptions = { + findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; + getNetworkClientById: NetworkController['getNetworkClientById']; +}; + +export default class MultichainSubscriptionManager extends SafeEventEmitter { + #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; + + #getNetworkClientById: NetworkController['getNetworkClientById']; + + #subscriptions: SubscriptionEntry[] = []; + + constructor(options: MultichainSubscriptionManagerOptions) { + super(); + this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId; + this.#getNetworkClientById = options.getNetworkClientById; + } + + onNotification( + { scope, origin, tabId }: SubscriptionKey, + { method, params }: SubscriptionNotificationEvent, + ) { + this.emit('notification', origin, tabId, { + method: 'wallet_notify', + params: { + scope, + notification: { method, params }, + }, + }); + } + + #getSubscriptionEntry({ + scope, + origin, + tabId, + }: SubscriptionKey): SubscriptionEntry | undefined { + return this.#subscriptions.find((subscriptionEntry) => { + return ( + subscriptionEntry.scope === scope && + subscriptionEntry.origin === origin && + subscriptionEntry.tabId === tabId + ); + }); + } + + #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionKey) { + this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => { + return ( + subscriptionEntry.scope !== scope || + subscriptionEntry.origin !== origin || + subscriptionEntry.tabId !== tabId + ); + }); + } + + subscribe(subscriptionKey: SubscriptionKey) { + const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey); + if (subscriptionEntry) { + return subscriptionEntry.subscriptionManager; + } + + const networkClientId = this.#findNetworkClientIdByChainId( + toHex(parseCaipChainId(subscriptionKey.scope).reference), + ); + const networkClient = this.#getNetworkClientById(networkClientId); + const subscriptionManager = createSubscriptionManager({ + blockTracker: networkClient.blockTracker, + provider: networkClient.provider, + }); + + subscriptionManager.events.on( + 'notification', + (message: SubscriptionNotificationEvent) => { + this.onNotification(subscriptionKey, message); + }, + ); + + this.#subscriptions.push({ + ...subscriptionKey, + subscriptionManager, + }); + + return subscriptionManager; + } + + #unsubscribe(subscriptionKey: SubscriptionKey) { + const existingSubscriptionEntry = + this.#getSubscriptionEntry(subscriptionKey); + if (!existingSubscriptionEntry) { + return; + } + + existingSubscriptionEntry.subscriptionManager.destroy?.(); + + this.#removeSubscriptionEntry(subscriptionKey); + } + + unsubscribeByScope(scope: ScopeString) { + this.#subscriptions.forEach((subscriptionEntry) => { + if (subscriptionEntry.scope === scope) { + this.#unsubscribe(subscriptionEntry); + } + }); + } + + unsubscribeByScopeAndOrigin(scope: ScopeString, origin: string) { + this.#subscriptions.forEach((subscriptionEntry) => { + if ( + subscriptionEntry.scope === scope && + subscriptionEntry.origin === origin + ) { + this.#unsubscribe(subscriptionEntry); + } + }); + } + + unsubscribeByOriginAndTabId(origin: string, tabId?: number) { + this.#subscriptions.forEach((subscriptionEntry) => { + if ( + subscriptionEntry.origin === origin && + subscriptionEntry.tabId === tabId + ) { + this.#unsubscribe(subscriptionEntry); + } + }); + } +} diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts new file mode 100644 index 00000000000..cff2841ecf9 --- /dev/null +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -0,0 +1,98 @@ +import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; +import { rpcErrors } from '@metamask/rpc-errors'; +import { + JsonRpcError, + JsonRpcParams, + JsonRpcRequest, + isObject, +} from '@metamask/utils'; +import { + ContentDescriptorObject, + MethodObject, + OpenrpcDocument, +} from '@open-rpc/meta-schema'; +import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; +import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; +import { Json, JsonRpcMiddleware } from 'json-rpc-engine'; +import { Schema, ValidationError, Validator } from 'jsonschema'; + +const transformError = ( + error: ValidationError, + param: ContentDescriptorObject, + got: unknown, +) => { + // if there is a path, add it to the message + const message = `${ + param.name + (error.path.length > 0 ? `.${error.path.join('.')}` : '') + } ${error.message}`; + + return { + code: -32602, // TODO: could be a different error code or not wrapped in json-rpc error, since this will also be wrapped in a -32602 invalid params error + message, + data: { + param: param.name, + path: error.path, + schema: error.schema, + got, + }, + }; +}; + +const v = new Validator(); + +const dereffedPromise = dereferenceDocument( + MultiChainOpenRPCDocument as unknown as OpenrpcDocument, + makeCustomResolver({}), +); +export const multichainMethodCallValidator = async ( + method: string, + params: JsonRpcParams | undefined, +) => { + const dereffed = await dereffedPromise; + const methodToCheck = dereffed.methods.find( + (m) => (m as unknown as ContentDescriptorObject).name === method, + ); + const errors: JsonRpcError[] = []; + // check each param and aggregate errors + (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { + let paramToCheck: Json | undefined; + const p = param as ContentDescriptorObject; + if (isObject(params)) { + paramToCheck = params[p.name]; + } else if (params && Array.isArray(params)) { + paramToCheck = params[i]; + } else { + paramToCheck = undefined; + } + const result = v.validate(paramToCheck, p.schema as unknown as Schema, { + required: p.required, + }); + if (result.errors) { + errors.push( + ...result.errors.map((e) => { + return transformError(e, p, paramToCheck) as JsonRpcError; + }), + ); + } + }); + if (errors.length > 0) { + return errors; + } + // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors + // would be an array and return true if it's empty + return false; +}; + +export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< + JsonRpcRequest, + void +> = function (request, _response, next, end) { + multichainMethodCallValidator(request.method, request.params).then( + (errors) => { + if (errors) { + return end(rpcErrors.invalidParams({ data: errors })); + } + return next(); + }, + ); +}; diff --git a/packages/multichain/tsconfig.build.json b/packages/multichain/tsconfig.build.json new file mode 100644 index 00000000000..02a0eea03fe --- /dev/null +++ b/packages/multichain/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.packages.build.json", + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist", + "rootDir": "./src" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/multichain/tsconfig.json b/packages/multichain/tsconfig.json new file mode 100644 index 00000000000..025ba2ef7f4 --- /dev/null +++ b/packages/multichain/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "baseUrl": "./" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/multichain/typedoc.json b/packages/multichain/typedoc.json new file mode 100644 index 00000000000..c9da015dbf8 --- /dev/null +++ b/packages/multichain/typedoc.json @@ -0,0 +1,7 @@ +{ + "entryPoints": ["./src/index.ts"], + "excludePrivate": true, + "hideGenerator": true, + "out": "docs", + "tsconfig": "./tsconfig.build.json" +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 4e485ea1896..6102878c563 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -18,6 +18,7 @@ { "path": "./packages/keyring-controller/tsconfig.build.json" }, { "path": "./packages/logging-controller/tsconfig.build.json" }, { "path": "./packages/message-manager/tsconfig.build.json" }, + { "path": "./packages/multichain/tsconfig.build.json" }, { "path": "./packages/name-controller/tsconfig.build.json" }, { "path": "./packages/network-controller/tsconfig.build.json" }, { "path": "./packages/notification-controller/tsconfig.build.json" }, diff --git a/tsconfig.json b/tsconfig.json index f886671a63c..127a643b9d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ { "path": "./packages/json-rpc-middleware-stream" }, { "path": "./packages/keyring-controller" }, { "path": "./packages/message-manager" }, + { "path": "./packages/multichain" }, { "path": "./packages/name-controller" }, { "path": "./packages/network-controller" }, { "path": "./packages/notification-controller" }, diff --git a/yarn.lock b/yarn.lock index 06a9e70928e..d59a9c957fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3010,6 +3010,21 @@ __metadata: languageName: node linkType: hard +"@metamask/multichain@workspace:packages/multichain": + version: 0.0.0-use.local + resolution: "@metamask/multichain@workspace:packages/multichain" + dependencies: + "@metamask/auto-changelog": "npm:^3.4.4" + "@types/jest": "npm:^27.4.1" + deepmerge: "npm:^4.2.2" + jest: "npm:^27.5.1" + ts-jest: "npm:^27.1.4" + typedoc: "npm:^0.24.8" + typedoc-plugin-missing-exports: "npm:^2.0.0" + typescript: "npm:~5.2.2" + languageName: unknown + linkType: soft + "@metamask/name-controller@workspace:packages/name-controller": version: 0.0.0-use.local resolution: "@metamask/name-controller@workspace:packages/name-controller" From a4b52ad4a567414d4b25098ddd37339a586937f4 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 14:17:39 -0700 Subject: [PATCH 002/146] Fix caip25Permission --- packages/multichain/package.json | 9 +++++++++ ...ermissions.test.ts => caip25Permission.test.ts} | 14 +++++++------- .../{caip25permissions.ts => caip25Permission.ts} | 10 +++++----- packages/multichain/tsconfig.json | 9 ++++++++- yarn.lock | 6 ++++++ 5 files changed, 35 insertions(+), 13 deletions(-) rename packages/multichain/src/{caip25permissions.test.ts => caip25Permission.test.ts} (98%) rename packages/multichain/src/{caip25permissions.ts => caip25Permission.ts} (96%) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index b7f05dcc3e0..9d65fa1eab6 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -39,8 +39,13 @@ "test:verbose": "jest --verbose", "test:watch": "jest --watch" }, + "dependencies": { + "lodash": "^4.17.21" + }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", + "@metamask/network-controller": "^21.0.1", + "@metamask/permission-controller": "^11.0.2", "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", "jest": "^27.5.1", @@ -49,6 +54,10 @@ "typedoc-plugin-missing-exports": "^2.0.0", "typescript": "~5.2.2" }, + "peerDependencies": { + "@metamask/network-controller": "^21.0.0", + "@metamask/permission-controller": "^11.0.0" + }, "engines": { "node": "^18.18 || >=20" }, diff --git a/packages/multichain/src/caip25permissions.test.ts b/packages/multichain/src/caip25Permission.test.ts similarity index 98% rename from packages/multichain/src/caip25permissions.test.ts rename to packages/multichain/src/caip25Permission.test.ts index 97fce8f631d..cf63cf0a0c2 100644 --- a/packages/multichain/src/caip25permissions.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -13,7 +13,7 @@ import { Caip25EndowmentPermissionName, Caip25CaveatMutatorFactories, removeScope, -} from './caip25permissions'; +} from './caip25Permission'; jest.mock('./scope', () => ({ validateAndFlattenScopes: jest.fn(), @@ -73,7 +73,7 @@ describe('endowment:caip25', () => { }; const result = removeScope('eip155:5', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.updateValue, + operation: CaveatMutatorOperation.UpdateValue, value: { requiredScopes: { 'eip155:1': { @@ -105,7 +105,7 @@ describe('endowment:caip25', () => { }; const result = removeScope('eip155:1', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.revokePermission, + operation: CaveatMutatorOperation.RevokePermission, }); }); @@ -128,7 +128,7 @@ describe('endowment:caip25', () => { }; const result = removeScope('eip155:2', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.noop, + operation: CaveatMutatorOperation.Noop, }); }); }); @@ -148,7 +148,7 @@ describe('endowment:caip25', () => { }; const result = removeAccount('0x1', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.updateValue, + operation: CaveatMutatorOperation.UpdateValue, value: { requiredScopes: { 'eip155:1': { @@ -188,7 +188,7 @@ describe('endowment:caip25', () => { }; const result = removeAccount('0x1', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.updateValue, + operation: CaveatMutatorOperation.UpdateValue, value: { requiredScopes: { 'eip155:1': { @@ -233,7 +233,7 @@ describe('endowment:caip25', () => { }; const result = removeAccount('0x3', ethereumGoerliCaveat); expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.noop, + operation: CaveatMutatorOperation.Noop, }); }); }); diff --git a/packages/multichain/src/caip25permissions.ts b/packages/multichain/src/caip25Permission.ts similarity index 96% rename from packages/multichain/src/caip25permissions.ts rename to packages/multichain/src/caip25Permission.ts index 335f17113a2..35312b2e11f 100644 --- a/packages/multichain/src/caip25permissions.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -191,12 +191,12 @@ function removeAccount( if (noChange) { return { - operation: CaveatMutatorOperation.noop, + operation: CaveatMutatorOperation.Noop, }; } return { - operation: CaveatMutatorOperation.updateValue, + operation: CaveatMutatorOperation.UpdateValue, value: copyOfExistingScopes, }; } @@ -231,13 +231,13 @@ export function removeScope( if (requiredScopesRemoved) { return { - operation: CaveatMutatorOperation.revokePermission, + operation: CaveatMutatorOperation.RevokePermission, }; } if (optionalScopesRemoved) { return { - operation: CaveatMutatorOperation.updateValue, + operation: CaveatMutatorOperation.UpdateValue, value: { requiredScopes: newRequiredScopes.reduce(reduceKeysHelper, {}), optionalScopes: newOptionalScopes.reduce(reduceKeysHelper, {}), @@ -246,6 +246,6 @@ export function removeScope( } return { - operation: CaveatMutatorOperation.noop, + operation: CaveatMutatorOperation.Noop, }; } diff --git a/packages/multichain/tsconfig.json b/packages/multichain/tsconfig.json index 025ba2ef7f4..34e1d4a7218 100644 --- a/packages/multichain/tsconfig.json +++ b/packages/multichain/tsconfig.json @@ -3,6 +3,13 @@ "compilerOptions": { "baseUrl": "./" }, - "references": [], + "references": [ + { + "path": "../network-controller" + }, + { + "path": "../permission-controller" + } + ], "include": ["../../types", "./src"] } diff --git a/yarn.lock b/yarn.lock index d59a9c957fe..93b7cecb5f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3015,13 +3015,19 @@ __metadata: resolution: "@metamask/multichain@workspace:packages/multichain" dependencies: "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/network-controller": "npm:^21.0.1" + "@metamask/permission-controller": "npm:^11.0.2" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" + lodash: "npm:^4.17.21" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" typedoc-plugin-missing-exports: "npm:^2.0.0" typescript: "npm:~5.2.2" + peerDependencies: + "@metamask/network-controller": ^21.0.0 + "@metamask/permission-controller": ^11.0.0 languageName: unknown linkType: soft From 86ab58a2690b7808304a29840ddc94d672c7420c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 14:40:07 -0700 Subject: [PATCH 003/146] scopes --- packages/multichain/package.json | 3 + packages/multichain/src/scope/assert.test.ts | 209 +++++++++++++ packages/multichain/src/scope/assert.ts | 73 +++++ .../src/scope/authorization.test.ts | 219 ++++++++++++++ .../multichain/src/scope/authorization.ts | 68 +++++ packages/multichain/src/scope/filter.test.ts | 153 ++++++++++ packages/multichain/src/scope/filter.ts | 43 +++ packages/multichain/src/scope/index.ts | 7 + packages/multichain/src/scope/scope.test.ts | 23 ++ packages/multichain/src/scope/scope.ts | 96 ++++++ .../multichain/src/scope/supported.test.ts | 96 ++++++ packages/multichain/src/scope/supported.ts | 126 ++++++++ .../multichain/src/scope/transform.test.ts | 283 ++++++++++++++++++ packages/multichain/src/scope/transform.ts | 119 ++++++++ .../multichain/src/scope/validation.test.ts | 177 +++++++++++ packages/multichain/src/scope/validation.ts | 101 +++++++ yarn.lock | 10 + 17 files changed, 1806 insertions(+) create mode 100644 packages/multichain/src/scope/assert.test.ts create mode 100644 packages/multichain/src/scope/assert.ts create mode 100644 packages/multichain/src/scope/authorization.test.ts create mode 100644 packages/multichain/src/scope/authorization.ts create mode 100644 packages/multichain/src/scope/filter.test.ts create mode 100644 packages/multichain/src/scope/filter.ts create mode 100644 packages/multichain/src/scope/index.ts create mode 100644 packages/multichain/src/scope/scope.test.ts create mode 100644 packages/multichain/src/scope/scope.ts create mode 100644 packages/multichain/src/scope/supported.test.ts create mode 100644 packages/multichain/src/scope/supported.ts create mode 100644 packages/multichain/src/scope/transform.test.ts create mode 100644 packages/multichain/src/scope/transform.ts create mode 100644 packages/multichain/src/scope/validation.test.ts create mode 100644 packages/multichain/src/scope/validation.ts diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 9d65fa1eab6..c284234ed55 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -40,10 +40,13 @@ "test:watch": "jest --watch" }, "dependencies": { + "@metamask/api-specs": "^0.10.12", + "@metamask/rpc-errors": "^6.3.1", "lodash": "^4.17.21" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", + "@metamask/json-rpc-engine": "^9.0.3", "@metamask/network-controller": "^21.0.1", "@metamask/permission-controller": "^11.0.2", "@types/jest": "^27.4.1", diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts new file mode 100644 index 00000000000..919b6e6a388 --- /dev/null +++ b/packages/multichain/src/scope/assert.test.ts @@ -0,0 +1,209 @@ +import { JsonRpcError } from '@metamask/rpc-errors'; +import { assertScopeSupported, assertScopesSupported } from './assert'; +import { ScopeObject } from './scope'; +import * as Supported from './supported'; + +jest.mock('./supported', () => ({ + isSupportedScopeString: jest.fn(), + isSupportedNotification: jest.fn(), + isSupportedMethod: jest.fn(), +})); +const MockSupported = jest.mocked(Supported); + +const validScopeObject: ScopeObject = { + methods: [], + notifications: [], +}; + +describe('Scope Assert', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('assertScopeSupported', () => { + const isChainIdSupported = jest.fn(); + + describe('scopeString', () => { + it('checks if the scopeString is supported', () => { + try { + assertScopeSupported('scopeString', validScopeObject, { + isChainIdSupported, + }); + } catch (err) { + // noop + } + expect(MockSupported.isSupportedScopeString).toHaveBeenCalledWith( + 'scopeString', + isChainIdSupported, + ); + }); + + it('throws an error if the scopeString is not supported', () => { + MockSupported.isSupportedScopeString.mockReturnValue(false); + expect(() => { + assertScopeSupported('scopeString', validScopeObject, { + isChainIdSupported, + }); + }).toThrow( + new JsonRpcError(5100, 'Requested chains are not supported'), + ); + }); + }); + + describe('scopeObject', () => { + beforeEach(() => { + MockSupported.isSupportedScopeString.mockReturnValue(true); + }); + + it('checks if the methods are supported', () => { + try { + assertScopeSupported( + 'scopeString', + { + ...validScopeObject, + methods: ['eth_chainId'], + }, + { + isChainIdSupported, + }, + ); + } catch (err) { + // noop + } + + expect(MockSupported.isSupportedMethod).toHaveBeenCalledWith( + 'scopeString', + 'eth_chainId', + ); + }); + + it('throws an error if there are unsupported methods', () => { + MockSupported.isSupportedMethod.mockReturnValue(false); + expect(() => { + assertScopeSupported( + 'scopeString', + { + ...validScopeObject, + methods: ['eth_chainId'], + }, + { + isChainIdSupported, + }, + ); + }).toThrow( + new JsonRpcError(5101, 'Requested methods are not supported'), + ); + }); + + it('checks if the notifications are supported', () => { + MockSupported.isSupportedMethod.mockReturnValue(true); + try { + assertScopeSupported( + 'scopeString', + { + ...validScopeObject, + notifications: ['chainChanged'], + }, + { + isChainIdSupported, + }, + ); + } catch (err) { + // noop + } + + expect(MockSupported.isSupportedNotification).toHaveBeenCalledWith( + 'scopeString', + 'chainChanged', + ); + }); + + it('throws an error if there are unsupported notifications', () => { + MockSupported.isSupportedMethod.mockReturnValue(true); + MockSupported.isSupportedNotification.mockReturnValue(false); + expect(() => { + assertScopeSupported( + 'scopeString', + { + ...validScopeObject, + notifications: ['chainChanged'], + }, + { + isChainIdSupported, + }, + ); + }).toThrow( + new JsonRpcError( + 5102, + 'Requested notifications are not supported', + ), + ); + }); + + it('does not throw if the scopeObject is valid', () => { + MockSupported.isSupportedMethod.mockReturnValue(true); + MockSupported.isSupportedNotification.mockReturnValue(true); + expect( + assertScopeSupported( + 'scopeString', + { + ...validScopeObject, + methods: ['eth_chainId'], + notifications: ['chainChanged'], + accounts: ['eip155:1:0xdeadbeef'], + }, + { + isChainIdSupported, + }, + ), + ).toBeUndefined(); + }); + }); + }); + + describe('assertScopesSupported', () => { + const isChainIdSupported = jest.fn(); + + it('does not throw an error if no scopes are defined', () => { + assertScopesSupported( + {}, + { + isChainIdSupported, + }, + ); + }); + + it('throws an error if any scope is invalid', () => { + MockSupported.isSupportedScopeString.mockReturnValue(false); + + expect(() => { + assertScopesSupported( + { + 'eip155:1': validScopeObject, + }, + { + isChainIdSupported, + }, + ); + }).toThrow( + new JsonRpcError(5100, 'Requested chains are not supported'), + ); + }); + + it('does not throw an error if all scopes are valid', () => { + MockSupported.isSupportedScopeString.mockReturnValue(true); + + expect( + assertScopesSupported( + { + 'eip155:1': validScopeObject, + 'eip155:2': validScopeObject, + }, + { + isChainIdSupported, + }, + ), + ).toBeUndefined(); + }); + }); +}); diff --git a/packages/multichain/src/scope/assert.ts b/packages/multichain/src/scope/assert.ts new file mode 100644 index 00000000000..2724ecd2214 --- /dev/null +++ b/packages/multichain/src/scope/assert.ts @@ -0,0 +1,73 @@ +import { Hex } from '@metamask/utils'; +import { JsonRpcError } from '@metamask/rpc-errors'; +import { + isSupportedMethod, + isSupportedNotification, + isSupportedScopeString, +} from './supported'; +import { ScopeObject, ScopesObject } from './scope'; + +export const assertScopeSupported = ( + scopeString: string, + scopeObject: ScopeObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + const { methods, notifications } = scopeObject; + if (!isSupportedScopeString(scopeString, isChainIdSupported)) { + throw new JsonRpcError(5100, 'Requested chains are not supported'); + } + + const allMethodsSupported = methods.every((method) => + isSupportedMethod(scopeString, method), + ); + + if (!allMethodsSupported) { + // not sure which one of these to use + // When provider evaluates requested methods to not be supported + // code = 5101 + // message = "Requested methods are not supported" + // When provider does not recognize one or more requested method(s) + // code = 5201 + // message = "Unknown method(s) requested" + + throw new JsonRpcError(5101, 'Requested methods are not supported'); + } + + if ( + notifications && + !notifications.every((notification) => + isSupportedNotification(scopeString, notification), + ) + ) { + // not sure which one of these to use + // When provider evaluates requested notifications to not be supported + // code = 5102 + // message = "Requested notifications are not supported" + // When provider does not recognize one or more requested notification(s) + // code = 5202 + // message = "Unknown notification(s) requested" + throw new JsonRpcError( + 5102, + 'Requested notifications are not supported', + ); + } +}; + +export const assertScopesSupported = ( + scopes: ScopesObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + for (const [scopeString, scopeObject] of Object.entries(scopes)) { + assertScopeSupported(scopeString, scopeObject, { + isChainIdSupported, + }); + } +}; diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts new file mode 100644 index 00000000000..69e57dc32ca --- /dev/null +++ b/packages/multichain/src/scope/authorization.test.ts @@ -0,0 +1,219 @@ +import * as Validation from './validation'; +import * as Transform from './transform'; +import * as Filter from './filter'; +import { + bucketScopes, + validateAndFlattenScopes, +} from './authorization'; +import { ExternalScopeObject } from './scope'; + +jest.mock('./validation', () => ({ + validateScopes: jest.fn(), +})); +const MockValidation = jest.mocked(Validation); + +jest.mock('./transform', () => ({ + flattenMergeScopes: jest.fn(), +})); +const MockTransform = jest.mocked(Transform); + +jest.mock('./filter', () => ({ + bucketScopesBySupport: jest.fn(), +})); +const MockFilter = jest.mocked(Filter); + +const validScopeObject: ExternalScopeObject = { + methods: [], + notifications: [], +}; + +describe('Scope Authorization', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('validateAndFlattenScopes', () => { + it('validates the scopes', () => { + try { + validateAndFlattenScopes( + { + 'eip155:1': validScopeObject, + }, + { + 'eip155:5': validScopeObject, + }, + ); + } catch (err) { + // noop + } + expect(MockValidation.validateScopes).toHaveBeenCalledWith( + { + 'eip155:1': validScopeObject, + }, + { + 'eip155:5': validScopeObject, + }, + ); + }); + + it('flatten and merges the validated scopes', () => { + MockValidation.validateScopes.mockReturnValue({ + validRequiredScopes: { + 'eip155:1': validScopeObject, + }, + validOptionalScopes: { + 'eip155:5': validScopeObject, + }, + }); + + validateAndFlattenScopes({}, {}); + expect(MockTransform.flattenMergeScopes).toHaveBeenCalledWith({ + 'eip155:1': validScopeObject, + }); + expect(MockTransform.flattenMergeScopes).toHaveBeenCalledWith({ + 'eip155:5': validScopeObject, + }); + }); + + it('returns the flattened and merged scopes', () => { + MockValidation.validateScopes.mockReturnValue({ + validRequiredScopes: { + 'eip155:1': validScopeObject, + }, + validOptionalScopes: { + 'eip155:5': validScopeObject, + }, + }); + MockTransform.flattenMergeScopes.mockImplementation((value) => ({ + ...value, + transformed: true, + })); + + expect(validateAndFlattenScopes({}, {})).toStrictEqual({ + flattenedRequiredScopes: { + 'eip155:1': validScopeObject, + transformed: true, + }, + flattenedOptionalScopes: { + 'eip155:5': validScopeObject, + transformed: true, + }, + }); + }); + }); + + describe('bucketScopes', () => { + beforeEach(() => { + let callCount = 0; + MockFilter.bucketScopesBySupport.mockImplementation(() => { + callCount += 1; + return { + supportedScopes: { + 'mock:A': { + methods: [`mock_method_${callCount}`], + notifications: [], + }, + }, + unsupportedScopes: { + 'mock:B': { + methods: [`mock_method_${callCount}`], + notifications: [], + }, + }, + }; + }); + }); + + it('buckets the scopes by supported', () => { + const isChainIdSupported = jest.fn(); + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + }, + }, + { + isChainIdSupported, + isChainIdSupportable: jest.fn(), + }, + ); + + expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( + { + wallet: { + methods: [], + notifications: [], + }, + }, + { + isChainIdSupported, + }, + ); + }); + + it('buckets the mayble supportable scopes', () => { + const isChainIdSupportable = jest.fn(); + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + }, + }, + { + isChainIdSupported: jest.fn(), + isChainIdSupportable, + }, + ); + + expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( + { + 'mock:B': { + methods: [`mock_method_1`], + notifications: [], + }, + }, + { + isChainIdSupported: isChainIdSupportable, + }, + ); + }); + + it('returns the bucketed scopes', () => { + expect( + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + }, + }, + { + isChainIdSupported: jest.fn(), + isChainIdSupportable: jest.fn(), + }, + ), + ).toStrictEqual({ + supportedScopes: { + 'mock:A': { + methods: [`mock_method_1`], + notifications: [], + }, + }, + supportableScopes: { + 'mock:A': { + methods: [`mock_method_2`], + notifications: [], + }, + }, + unsupportableScopes: { + 'mock:B': { + methods: [`mock_method_2`], + notifications: [], + }, + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts new file mode 100644 index 00000000000..b6c83cb1cf6 --- /dev/null +++ b/packages/multichain/src/scope/authorization.ts @@ -0,0 +1,68 @@ +import { validateScopes } from './validation'; +import { ExternalScopesObject, ScopesObject, ScopedProperties } from './scope'; +import { flattenMergeScopes } from './transform'; +import { bucketScopesBySupport } from './filter'; +import { Hex } from '@metamask/utils'; + +export type Caip25Authorization = + | { + requiredScopes: ExternalScopesObject; + optionalScopes?: ExternalScopesObject; + sessionProperties?: Record; + } + | ({ + requiredScopes?: ExternalScopesObject; + optionalScopes: ExternalScopesObject; + } & { + sessionProperties?: Record; + }); + +export const validateAndFlattenScopes = ( + requiredScopes: ExternalScopesObject, + optionalScopes: ExternalScopesObject, +): { + flattenedRequiredScopes: ScopesObject; + flattenedOptionalScopes: ScopesObject; +} => { + const { validRequiredScopes, validOptionalScopes } = validateScopes( + requiredScopes, + optionalScopes, + ); + + const flattenedRequiredScopes = flattenMergeScopes(validRequiredScopes); + const flattenedOptionalScopes = flattenMergeScopes(validOptionalScopes); + + return { + flattenedRequiredScopes, + flattenedOptionalScopes, + }; +}; + +export const bucketScopes = ( + scopes: ScopesObject, + { + isChainIdSupported, + isChainIdSupportable, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + isChainIdSupportable: (chainId: Hex) => boolean; + }, +): { + supportedScopes: ScopesObject; + supportableScopes: ScopesObject; + unsupportableScopes: ScopesObject; +} => { + const { supportedScopes, unsupportedScopes: maybeSupportableScopes } = + bucketScopesBySupport(scopes, { + isChainIdSupported, + }); + + const { + supportedScopes: supportableScopes, + unsupportedScopes: unsupportableScopes, + } = bucketScopesBySupport(maybeSupportableScopes, { + isChainIdSupported: isChainIdSupportable, + }); + + return { supportedScopes, supportableScopes, unsupportableScopes }; +}; diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts new file mode 100644 index 00000000000..cf7c4925834 --- /dev/null +++ b/packages/multichain/src/scope/filter.test.ts @@ -0,0 +1,153 @@ +import * as Assert from './assert'; +import { filterScopesSupported, bucketScopesBySupport } from './filter'; + +jest.mock('./assert', () => ({ + assertScopeSupported: jest.fn(), +})); +const MockAssert = jest.mocked(Assert); + +describe('filter', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('filterScopesSupported', () => { + const isChainIdSupported = jest.fn(); + + it('checks if each scope is supported', () => { + filterScopesSupported( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }, + { isChainIdSupported }, + ); + + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:1', + { + methods: ['a'], + notifications: [], + }, + { isChainIdSupported }, + ); + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:5', + { + methods: ['b'], + notifications: [], + }, + { isChainIdSupported }, + ); + }); + + it('returns only supported scopes', () => { + MockAssert.assertScopeSupported.mockImplementation((scopeString) => { + if (scopeString === 'eip155:1') { + throw new Error('scope not supported'); + } + }); + + expect( + filterScopesSupported( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }, + { isChainIdSupported }, + ), + ).toStrictEqual({ + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }); + }); + }); + + describe('bucketScopesBySupport', () => { + const isChainIdSupported = jest.fn(); + + it('checks if each scope is supported', () => { + bucketScopesBySupport( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }, + { isChainIdSupported }, + ); + + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:1', + { + methods: ['a'], + notifications: [], + }, + { isChainIdSupported }, + ); + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:5', + { + methods: ['b'], + notifications: [], + }, + { isChainIdSupported }, + ); + }); + + it('returns supported and unsupported scopes', () => { + MockAssert.assertScopeSupported.mockImplementation((scopeString) => { + if (scopeString === 'eip155:1') { + throw new Error('scope not supported'); + } + }); + + expect( + bucketScopesBySupport( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }, + { isChainIdSupported }, + ), + ).toStrictEqual({ + supportedScopes: { + 'eip155:5': { + methods: ['b'], + notifications: [], + }, + }, + unsupportedScopes: { + 'eip155:1': { + methods: ['a'], + notifications: [], + }, + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts new file mode 100644 index 00000000000..06b9795c497 --- /dev/null +++ b/packages/multichain/src/scope/filter.ts @@ -0,0 +1,43 @@ +import { CaipChainId, Hex } from '@metamask/utils'; +import { ScopesObject } from './scope'; +import { assertScopeSupported } from './assert'; + +export const bucketScopesBySupport = ( + scopes: ScopesObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + const supportedScopes: ScopesObject = {}; + const unsupportedScopes: ScopesObject = {}; + + for (const [scopeString, scopeObject] of Object.entries(scopes)) { + try { + assertScopeSupported(scopeString, scopeObject, { + isChainIdSupported, + }); + supportedScopes[scopeString as CaipChainId] = scopeObject; + } catch (err) { + unsupportedScopes[scopeString as CaipChainId] = scopeObject; + } + } + + return { supportedScopes, unsupportedScopes }; +}; + +export const filterScopesSupported = ( + scopes: ScopesObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + const { supportedScopes } = bucketScopesBySupport(scopes, { + isChainIdSupported, + }); + + return supportedScopes; +}; diff --git a/packages/multichain/src/scope/index.ts b/packages/multichain/src/scope/index.ts new file mode 100644 index 00000000000..c1b804efecb --- /dev/null +++ b/packages/multichain/src/scope/index.ts @@ -0,0 +1,7 @@ +export * from './assert'; +export * from './authorization'; +export * from './filter'; +export * from './scope'; +export * from './supported'; +export * from './transform'; +export * from './validation'; diff --git a/packages/multichain/src/scope/scope.test.ts b/packages/multichain/src/scope/scope.test.ts new file mode 100644 index 00000000000..2441c41c348 --- /dev/null +++ b/packages/multichain/src/scope/scope.test.ts @@ -0,0 +1,23 @@ +import { parseScopeString } from './scope'; + +describe('Scope', () => { + describe('parseScopeString', () => { + it('returns only the namespace if scopeString is namespace', () => { + expect(parseScopeString('abc')).toStrictEqual({ namespace: 'abc' }); + }); + + it('returns the namespace and reference if scopeString is a CAIP chain ID ', () => { + expect(parseScopeString('abc:foo')).toStrictEqual({ + namespace: 'abc', + reference: 'foo', + }); + }); + + it('returns empty object if scopeString is invalid', () => { + expect(parseScopeString('')).toStrictEqual({}); + expect(parseScopeString('a:')).toStrictEqual({}); + expect(parseScopeString(':b')).toStrictEqual({}); + expect(parseScopeString('a:b:c')).toStrictEqual({}); + }); + }); +}); diff --git a/packages/multichain/src/scope/scope.ts b/packages/multichain/src/scope/scope.ts new file mode 100644 index 00000000000..ae452ee6536 --- /dev/null +++ b/packages/multichain/src/scope/scope.ts @@ -0,0 +1,96 @@ +import MetaMaskOpenRPCDocument from '@metamask/api-specs'; +import { + CaipChainId, + CaipReference, + CaipAccountId, + isCaipNamespace, + isCaipChainId, + parseCaipChainId, + KnownCaipNamespace, + CaipNamespace, +} from '@metamask/utils'; + +export type NonWalletKnownCaipNamespace = Exclude< + KnownCaipNamespace, + KnownCaipNamespace.Wallet +>; + +export const KnownWalletRpcMethods: string[] = [ + 'wallet_registerOnboarding', + 'wallet_scanQRCode', +]; +const WalletEip155Methods = ['wallet_addEthereumChain']; + +const Eip155Methods = MetaMaskOpenRPCDocument.methods + .map(({ name }: { name: string}) => name) + .filter((method: string) => !WalletEip155Methods.includes(method)) + .filter((method: string) => !KnownWalletRpcMethods.includes(method)); + +export const KnownRpcMethods: Record = { + eip155: Eip155Methods, +}; + +export const KnownWalletNamespaceRpcMethods: Record< + NonWalletKnownCaipNamespace, + string[] +> = { + eip155: WalletEip155Methods, +}; + +export const KnownNotifications: Record = + { + eip155: ['accountsChanged', 'chainChanged', 'eth_subscription'], + }; + +// These External prefixed types represent the CAIP-217 +// Scope and ScopeObject as defined in the spec. +export type ExternalScopeString = CaipChainId | CaipNamespace; +export type ExternalScopeObject = ScopeObject & { + references?: CaipReference[]; +}; +export type ExternalScopesObject = Record< + ExternalScopeString, + ExternalScopeObject +>; + +// These non-prefixed types represent CAIP-217 Scope and +// ScopeObject as defined by the spec but without +// namespace-only Scopes (except for "wallet") and without +// the `references` array of CAIP References on the ScopeObject. +// These deviations from the spec are necessary as MetaMask +// does not support wildcarded Scopes, i.e. Scopes that only +// specify a namespace but no specific reference. +export type ScopeString = CaipChainId | KnownCaipNamespace.Wallet; +export type ScopeObject = { + methods: string[]; + notifications: string[]; + accounts?: CaipAccountId[]; + rpcDocuments?: string[]; + rpcEndpoints?: string[]; +}; +export type ScopesObject = Record & { + [KnownCaipNamespace.Wallet]?: ScopeObject; +}; + +export const parseScopeString = ( + scopeString: string, +): { + namespace?: string; + reference?: string; +} => { + if (isCaipNamespace(scopeString)) { + return { + namespace: scopeString, + }; + } + if (isCaipChainId(scopeString)) { + return parseCaipChainId(scopeString); + } + + return {}; +}; + +export type ScopedProperties = Record< + ExternalScopeString, + Record +>; diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts new file mode 100644 index 00000000000..30b85491079 --- /dev/null +++ b/packages/multichain/src/scope/supported.test.ts @@ -0,0 +1,96 @@ +import { + isSupportedMethod, + isSupportedNotification, + isSupportedScopeString, +} from './supported'; +import { + KnownNotifications, + KnownRpcMethods, + KnownWalletNamespaceRpcMethods, + KnownWalletRpcMethods, +} from './scope'; + +describe('Scope Support', () => { + describe('isSupportedNotification', () => { + it.each(Object.entries(KnownNotifications))( + 'returns true for each %s scope method', + (scopeString: string, notifications: string[]) => { + notifications.forEach((notification) => { + expect( + isSupportedNotification(scopeString, notification), + ).toStrictEqual(true); + }); + }, + ); + + it('returns false otherwise', () => { + expect(isSupportedNotification('eip155', 'anything else')).toStrictEqual( + false, + ); + expect(isSupportedNotification('', '')).toStrictEqual(false); + }); + }); + + describe('isSupportedMethod', () => { + it.each(Object.entries(KnownRpcMethods))( + 'returns true for each %s scoped method', + (scopeString: string, methods: string[]) => { + methods.forEach((method) => { + expect(isSupportedMethod(scopeString, method)).toStrictEqual(true); + }); + }, + ); + + it('returns true for each wallet scoped method', () => { + KnownWalletRpcMethods.forEach((method) => { + expect(isSupportedMethod('wallet', method)).toStrictEqual(true); + }); + }); + + it.each(Object.entries(KnownWalletNamespaceRpcMethods))( + 'returns true for each wallet:%s scoped method', + (scopeString: string, methods: string[]) => { + methods.forEach((method) => { + expect( + isSupportedMethod(`wallet:${scopeString}`, method), + ).toStrictEqual(true); + }); + }, + ); + + it('returns false otherwise', () => { + expect(isSupportedMethod('eip155', 'anything else')).toStrictEqual(false); + expect(isSupportedMethod('', '')).toStrictEqual(false); + }); + }); + + describe('isSupportedScopeString', () => { + it('returns true for the wallet namespace', () => { + expect(isSupportedScopeString('wallet', jest.fn())).toStrictEqual(true); + }); + + it('returns false for the wallet namespace when a reference is included', () => { + expect(isSupportedScopeString('wallet:someref', jest.fn())).toStrictEqual( + false, + ); + }); + + it('returns true for the ethereum namespace', () => { + expect(isSupportedScopeString('eip155', jest.fn())).toStrictEqual(true); + }); + + it('returns true for the ethereum namespace when a network client exists for the reference', () => { + const isChainIdSupportedMock = jest.fn().mockReturnValue(true); + expect( + isSupportedScopeString('eip155:1', isChainIdSupportedMock), + ).toStrictEqual(true); + }); + + it('returns false for the ethereum namespace when a network client does not exist for the reference', () => { + const isChainIdSupportedMock = jest.fn().mockReturnValue(false); + expect( + isSupportedScopeString('eip155:1', isChainIdSupportedMock), + ).toStrictEqual(false); + }); + }); +}); diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts new file mode 100644 index 00000000000..9ca98be6e23 --- /dev/null +++ b/packages/multichain/src/scope/supported.ts @@ -0,0 +1,126 @@ +import { + CaipAccountId, + Hex, + isCaipChainId, + isCaipNamespace, + KnownCaipNamespace, + parseCaipAccountId, + parseCaipChainId, +} from '@metamask/utils'; +import { toHex } from '@metamask/controller-utils'; +import { InternalAccount } from '@metamask/keyring-api'; +import { + KnownNotifications, + KnownRpcMethods, + KnownWalletNamespaceRpcMethods, + KnownWalletRpcMethods, + NonWalletKnownCaipNamespace, + parseScopeString, + ExternalScopeString, +} from './scope'; + +// TODO Maybe this gets DRY'ed into utils?.. It's used in TokenDetectionController too +function isEqualCaseInsensitive( + value1: string, + value2: string, +): boolean { + if (typeof value1 !== 'string' || typeof value2 !== 'string') { + return false; + } + return value1.toLowerCase() === value2.toLowerCase(); +} + +export const isSupportedScopeString = ( + scopeString: string, + isChainIdSupported: (chainId: Hex) => boolean, +) => { + const isNamespaceScoped = isCaipNamespace(scopeString); + const isChainScoped = isCaipChainId(scopeString); + + if (isNamespaceScoped) { + switch (scopeString) { + case KnownCaipNamespace.Wallet: + return true; + case KnownCaipNamespace.Eip155: + return true; + default: + return false; + } + } + + if (isChainScoped) { + const { namespace, reference } = parseCaipChainId(scopeString); + switch (namespace) { + case KnownCaipNamespace.Wallet: + if (reference === KnownCaipNamespace.Eip155) { + return true; + } + return false; + case KnownCaipNamespace.Eip155: + return isChainIdSupported(toHex(reference)); + default: + return false; + } + } + + return false; +}; + +export const isSupportedAccount = ( + account: CaipAccountId, + getInternalAccounts: () => InternalAccount[], +) => { + const { + address, + chain: { namespace }, + } = parseCaipAccountId(account); + switch (namespace) { + case KnownCaipNamespace.Eip155: + try { + return getInternalAccounts().some( + (internalAccount) => + ['eip155:eoa', 'eip155:erc4337'].includes(internalAccount.type) && + isEqualCaseInsensitive(address, internalAccount.address), + ); + } catch (err) { + console.log('failed to check if account is supported by wallet', err); + } + return false; + default: + return false; + } +}; + +export const isSupportedMethod = ( + scopeString: ExternalScopeString, + method: string, +): boolean => { + const { namespace, reference } = parseScopeString(scopeString); + + if (namespace === KnownCaipNamespace.Wallet) { + if (reference) { + return ( + KnownWalletNamespaceRpcMethods[ + reference as NonWalletKnownCaipNamespace + ] || [] + ).includes(method); + } + + return KnownWalletRpcMethods.includes(method); + } + + return ( + KnownRpcMethods[namespace as NonWalletKnownCaipNamespace] || [] + ).includes(method); +}; + +export const isSupportedNotification = ( + scopeString: ExternalScopeString, + notification: string, +): boolean => { + const { namespace } = parseScopeString(scopeString); + + return ( + KnownNotifications[namespace as NonWalletKnownCaipNamespace] || [] + ).includes(notification); +}; diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts new file mode 100644 index 00000000000..df0b529822f --- /dev/null +++ b/packages/multichain/src/scope/transform.test.ts @@ -0,0 +1,283 @@ +import { ExternalScopeObject } from './scope'; +import { + flattenScope, + mergeScopes, + mergeScopeObject, + flattenMergeScopes, +} from './transform'; + +const validScopeObject: ExternalScopeObject = { + methods: [], + notifications: [], +}; + +describe('Scope Transform', () => { + describe('flattenScope', () => { + it('returns the scope as is when the scopeString is chain scoped', () => { + expect(flattenScope('eip155:1', validScopeObject)).toStrictEqual({ + 'eip155:1': validScopeObject, + }); + }); + + describe('scopeString is namespace scoped', () => { + it('returns the scope as is when `references` is not defined', () => { + expect(flattenScope('eip155', validScopeObject)).toStrictEqual({ + eip155: validScopeObject, + }); + }); + + it('returns one scope per `references` element with `references` excluded from the scopeObject', () => { + expect( + flattenScope('eip155', { + ...validScopeObject, + references: ['1', '5', '64'], + }), + ).toStrictEqual({ + 'eip155:1': validScopeObject, + 'eip155:5': validScopeObject, + 'eip155:64': validScopeObject, + }); + }); + + it('returns one deep cloned scope per `references` element', () => { + const flattenedScopes = flattenScope('eip155', { + ...validScopeObject, + references: ['1', '5'], + }); + + expect(flattenedScopes['eip155:1']).not.toBe( + flattenedScopes['eip155:5'], + ); + expect(flattenedScopes['eip155:1'].methods).not.toBe( + flattenedScopes['eip155:5'].methods, + ); + }); + }); + }); + + describe('mergeScopeObject', () => { + it('returns an object with the unique set of methods', () => { + expect( + mergeScopeObject( + { + ...validScopeObject, + methods: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + methods: ['b', 'c', 'd'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + methods: ['a', 'b', 'c', 'd'], + }); + }); + + it('returns an object with the unique set of notifications', () => { + expect( + mergeScopeObject( + { + ...validScopeObject, + notifications: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + notifications: ['b', 'c', 'd'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + notifications: ['a', 'b', 'c', 'd'], + }); + }); + + it('returns an object with the unique set of accounts', () => { + expect( + mergeScopeObject( + { + ...validScopeObject, + accounts: ['eip155:1:a', 'eip155:1:b', 'eip155:1:c'], + }, + { + ...validScopeObject, + accounts: ['eip155:1:b', 'eip155:1:c', 'eip155:1:d'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + accounts: ['eip155:1:a', 'eip155:1:b', 'eip155:1:c', 'eip155:1:d'], + }); + + expect( + mergeScopeObject( + { + ...validScopeObject, + accounts: ['eip155:1:a', 'eip155:1:b', 'eip155:1:c'], + }, + { + ...validScopeObject, + }, + ), + ).toStrictEqual({ + ...validScopeObject, + accounts: ['eip155:1:a', 'eip155:1:b', 'eip155:1:c'], + }); + }); + + it('returns an object with the unique set of rpcDocuments', () => { + expect( + mergeScopeObject( + { + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + rpcDocuments: ['b', 'c', 'd'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c', 'd'], + }); + + expect( + mergeScopeObject( + { + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c'], + }); + }); + + it('returns an object with the unique set of rpcEndpoints', () => { + expect( + mergeScopeObject( + { + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + rpcEndpoints: ['b', 'c', 'd'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c', 'd'], + }); + + expect( + mergeScopeObject( + { + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c'], + }, + { + ...validScopeObject, + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c'], + }); + }); + }); + + describe('mergeScopes', () => { + it('merges the scopeObjects with matching scopeString', () => { + expect( + mergeScopes( + { + 'eip155:1': { + methods: ['a', 'b', 'c'], + notifications: ['foo'], + }, + }, + { + 'eip155:1': { + methods: ['c', 'd'], + notifications: ['bar'], + }, + }, + ), + ).toStrictEqual({ + 'eip155:1': { + methods: ['a', 'b', 'c', 'd'], + notifications: ['foo', 'bar'], + }, + }); + }); + + it('preserves the scopeObjects with no matching scopeString', () => { + expect( + mergeScopes( + { + 'eip155:1': { + methods: ['a', 'b', 'c'], + notifications: ['foo'], + }, + }, + { + 'eip155:2': { + methods: ['c', 'd'], + notifications: ['bar'], + }, + 'eip155:3': { + methods: [], + notifications: [], + }, + }, + ), + ).toStrictEqual({ + 'eip155:1': { + methods: ['a', 'b', 'c'], + notifications: ['foo'], + }, + 'eip155:2': { + methods: ['c', 'd'], + notifications: ['bar'], + }, + 'eip155:3': { + methods: [], + notifications: [], + }, + }); + }); + }); + + describe('flattenMergeScopes', () => { + it('flattens scopes and merges any overlapping scopeStrings', () => { + expect( + flattenMergeScopes({ + eip155: { + ...validScopeObject, + methods: ['a', 'b'], + references: ['1', '5'], + }, + 'eip155:1': { + ...validScopeObject, + methods: ['b', 'c', 'd'], + }, + }), + ).toStrictEqual({ + 'eip155:1': { + ...validScopeObject, + methods: ['a', 'b', 'c', 'd'], + }, + 'eip155:5': { + ...validScopeObject, + methods: ['a', 'b'], + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts new file mode 100644 index 00000000000..a31faf2d34c --- /dev/null +++ b/packages/multichain/src/scope/transform.ts @@ -0,0 +1,119 @@ +import { CaipReference } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; +import { + ExternalScopeObject, + ExternalScopesObject, + ScopeString, + ScopeObject, + ScopesObject, + parseScopeString, +} from './scope'; + +// DRY THIS +function unique(list: T[]): T[] { + return Array.from(new Set(list)); +} + +/** + * Flattens a ScopeString and ScopeObject into a separate + * ScopeString and ScopeObject for each reference in the `references` + * value if defined. Returns the ScopeString and ScopeObject + * unmodified if it cannot be flattened + * + * @param scopeString - The string representing the scopeObject + * @param scopeObject - The object that defines the scope + * @returns a map of caipChainId to ScopeObjects + */ +export const flattenScope = ( + scopeString: string, + scopeObject: ExternalScopeObject, +): ScopesObject => { + const { references, ...restScopeObject } = scopeObject; + const { namespace, reference } = parseScopeString(scopeString); + + // Scope is already a CAIP-2 ID and has no references to flatten + if (reference || !references) { + return { [scopeString]: scopeObject }; + } + + const scopeMap: ScopesObject = {}; + references.forEach((nestedReference: CaipReference) => { + scopeMap[`${namespace}:${nestedReference}`] = cloneDeep(restScopeObject); + }); + return scopeMap; +}; + +export const mergeScopeObject = ( + scopeObjectA: ScopeObject, + scopeObjectB: ScopeObject, +) => { + const mergedScopeObject: ScopeObject = { + methods: unique([...scopeObjectA.methods, ...scopeObjectB.methods]), + notifications: unique([ + ...scopeObjectA.notifications, + ...scopeObjectB.notifications, + ]), + }; + + if (scopeObjectA.accounts || scopeObjectB.accounts) { + mergedScopeObject.accounts = unique([ + ...(scopeObjectA.accounts ?? []), + ...(scopeObjectB.accounts ?? []), + ]); + } + + if (scopeObjectA.rpcDocuments || scopeObjectB.rpcDocuments) { + mergedScopeObject.rpcDocuments = unique([ + ...(scopeObjectA.rpcDocuments ?? []), + ...(scopeObjectB.rpcDocuments ?? []), + ]); + } + + if (scopeObjectA.rpcEndpoints || scopeObjectB.rpcEndpoints) { + mergedScopeObject.rpcEndpoints = unique([ + ...(scopeObjectA.rpcEndpoints ?? []), + ...(scopeObjectB.rpcEndpoints ?? []), + ]); + } + + return mergedScopeObject; +}; + +export const mergeScopes = ( + scopeA: ScopesObject, + scopeB: ScopesObject, +): ScopesObject => { + const scope: ScopesObject = {}; + + Object.entries(scopeA).forEach(([_scopeString, scopeObjectA]) => { + const scopeString = _scopeString as ScopeString; + const scopeObjectB = scopeB[scopeString]; + + scope[scopeString] = scopeObjectB + ? mergeScopeObject(scopeObjectA, scopeObjectB) + : scopeObjectA; + }); + + Object.entries(scopeB).forEach(([_scopeString, scopeObjectB]) => { + const scopeString = _scopeString as ScopeString; + const scopeObjectA = scopeA[scopeString]; + + if (!scopeObjectA) { + scope[scopeString] = scopeObjectB; + } + }); + + return scope; +}; + +export const flattenMergeScopes = ( + scopes: ExternalScopesObject, +): ScopesObject => { + let flattenedScopes: ScopesObject = {}; + Object.keys(scopes).forEach((scopeString) => { + const flattenedScopeMap = flattenScope(scopeString, scopes[scopeString]); + flattenedScopes = mergeScopes(flattenedScopes, flattenedScopeMap); + }); + + return flattenedScopes; +}; diff --git a/packages/multichain/src/scope/validation.test.ts b/packages/multichain/src/scope/validation.test.ts new file mode 100644 index 00000000000..507f24b328b --- /dev/null +++ b/packages/multichain/src/scope/validation.test.ts @@ -0,0 +1,177 @@ +import { ExternalScopeObject } from './scope'; +import { + isValidScope, + validateScopes, +} from './validation'; + +const validScopeString = 'eip155:1'; +const validScopeObject: ExternalScopeObject = { + methods: [], + notifications: [], +}; + +describe('Scope Validation', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('isValidScope', () => { + it.each([ + [ + false, + 'the scopeString is neither a CAIP namespace or CAIP chainId', + 'not a namespace or a caip chain id', + validScopeObject, + ], + [ + true, + 'the scopeString is a valid CAIP namespace and the scopeObject is valid', + 'eip155', + validScopeObject, + ], + [ + true, + 'the scopeString is a valid CAIP chainId and the scopeObject is valid', + 'eip155:1', + validScopeObject, + ], + [ + false, + 'the scopeString is a CAIP chainId but references is nonempty', + 'eip155:1', + { + ...validScopeObject, + references: ['5'], + }, + ], + [ + false, + 'methods contains empty string', + validScopeString, + { + ...validScopeObject, + methods: [''], + }, + ], + [ + false, + 'methods contains non-string', + validScopeString, + { + ...validScopeObject, + methods: [{ foo: 'bar' }], + }, + ], + [ + true, + 'methods contains only strings', + validScopeString, + { + ...validScopeObject, + methods: ['method1', 'method2'], + }, + ], + [ + false, + 'notifications contains empty string', + validScopeString, + { + ...validScopeObject, + notifications: [''], + }, + ], + [ + false, + 'notifications contains non-string', + validScopeString, + { + ...validScopeObject, + notifications: [{ foo: 'bar' }], + }, + ], + [ + false, + 'notifications contains non-string', + 'eip155:1', + { + ...validScopeObject, + notifications: [{ foo: 'bar' }], + }, + ], + [ + false, + 'unexpected properties are defined', + validScopeString, + { + ...validScopeObject, + unexpectedParam: 'foobar', + }, + ], + [ + true, + 'only expected properties are defined', + validScopeString, + { + references: [], + methods: [], + notifications: [], + accounts: [], + rpcDocuments: [], + rpcEndpoints: [], + }, + ], + ])( + 'returns %s when %s', + ( + expected: boolean, + _scenario: string, + scopeString: string, + scopeObject: unknown, + ) => { + expect(isValidScope(scopeString, scopeObject as ExternalScopeObject)).toStrictEqual(expected); + }, + ); + }); + + describe('validateScopes', () => { + const validScopeObjectWithAccounts = { + ...validScopeObject, + accounts: [], + }; + + it('does not throw an error if required scopes are defined but none are valid', () => { + validateScopes( + { 'eip155:1': {} as unknown as ExternalScopeObject }, + undefined, + ); + }); + + it('does not throw an error if optional scopes are defined but none are valid', () => { + validateScopes(undefined, { + 'eip155:1': {} as unknown as ExternalScopeObject, + }); + }); + + it('returns the valid required and optional scopes', () => { + expect( + validateScopes( + { + 'eip155:1': validScopeObjectWithAccounts, + 'eip155:64': {} as unknown as ExternalScopeObject, + }, + { + 'eip155:2': {} as unknown as ExternalScopeObject, + 'eip155:5': validScopeObjectWithAccounts, + }, + ), + ).toStrictEqual({ + validRequiredScopes: { + 'eip155:1': validScopeObjectWithAccounts, + }, + validOptionalScopes: { + 'eip155:5': validScopeObjectWithAccounts, + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/scope/validation.ts b/packages/multichain/src/scope/validation.ts new file mode 100644 index 00000000000..8a5ab1a1cdf --- /dev/null +++ b/packages/multichain/src/scope/validation.ts @@ -0,0 +1,101 @@ +import { isCaipReference } from '@metamask/utils'; +import { + ExternalScopeString, + parseScopeString, + ExternalScopeObject, + ExternalScopesObject, +} from './scope'; + +export const isValidScope = ( + scopeString: ExternalScopeString, + scopeObject: ExternalScopeObject, +): boolean => { + const { namespace, reference } = parseScopeString(scopeString); + + if (!namespace && !reference) { + return false; + } + + const { + references, + methods, + notifications, + accounts, + rpcDocuments, + rpcEndpoints, + ...restScopeObject + } = scopeObject; + + if (!methods || !notifications) { + return false; + } + + // These assume that the namespace has a notion of chainIds + if (reference && references && references.length > 0) { + return false; + } + if (namespace && references) { + const areReferencesValid = references.every((nestedReference) => { + return isCaipReference(nestedReference); + }); + + if (!areReferencesValid) { + return false; + } + } + + const areMethodsValid = methods.every( + (method) => typeof method === 'string' && method !== '', + ); + if (!areMethodsValid) { + return false; + } + + const areNotificationsValid = notifications.every( + (notification) => typeof notification === 'string' && notification !== '', + ); + if (!areNotificationsValid) { + return false; + } + + // unexpected properties found on scopeObject + if (Object.keys(restScopeObject).length !== 0) { + return false; + } + + return true; +}; + +export const validateScopes = ( + requiredScopes?: ExternalScopesObject, + optionalScopes?: ExternalScopesObject, +) => { + const validRequiredScopes: ExternalScopesObject = {}; + for (const [scopeString, scopeObject] of Object.entries( + requiredScopes || {}, + )) { + if (isValidScope(scopeString, scopeObject)) { + validRequiredScopes[scopeString] = { + accounts: [], + ...scopeObject, + }; + } + } + + const validOptionalScopes: ExternalScopesObject = {}; + for (const [scopeString, scopeObject] of Object.entries( + optionalScopes || {}, + )) { + if (isValidScope(scopeString, scopeObject)) { + validOptionalScopes[scopeString] = { + accounts: [], + ...scopeObject, + }; + } + } + + return { + validRequiredScopes, + validOptionalScopes, + }; +}; diff --git a/yarn.lock b/yarn.lock index 93b7cecb5f4..a3e97ad38dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2103,6 +2103,13 @@ __metadata: languageName: unknown linkType: soft +"@metamask/api-specs@npm:^0.10.12": + version: 0.10.12 + resolution: "@metamask/api-specs@npm:0.10.12" + checksum: 10/e592f27f350994688d3d54a8a8db16de033011ef665efe3283a77431914d8d69d1c3312fad33e4245b4984e1223b04c98da3d0a68c7f9577cf8290ba441c52ee + languageName: node + linkType: hard + "@metamask/approval-controller@npm:^7.0.2, @metamask/approval-controller@npm:^7.1.0, @metamask/approval-controller@workspace:packages/approval-controller": version: 0.0.0-use.local resolution: "@metamask/approval-controller@workspace:packages/approval-controller" @@ -3014,9 +3021,12 @@ __metadata: version: 0.0.0-use.local resolution: "@metamask/multichain@workspace:packages/multichain" dependencies: + "@metamask/api-specs": "npm:^0.10.12" "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" + "@metamask/rpc-errors": "npm:^6.3.1" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" From 186d4b34a2bd4e430ab0bb72023c3fb54a57710a Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 15:03:16 -0700 Subject: [PATCH 004/146] Fix middlewares --- packages/multichain/package.json | 3 + .../MultichainMiddlewareManager.test.ts | 14 +- .../MultichainMiddlewareManager.ts | 7 +- .../MultichainSubscriptionManager.test.ts | 25 ++- .../MultichainSubscriptionManager.ts | 10 +- .../multichainMethodCallValidator.ts | 5 +- types/@metamask/eth-json-rpc-filters.d.ts | 1 + yarn.lock | 145 +++++++++++++++++- 8 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 types/@metamask/eth-json-rpc-filters.d.ts diff --git a/packages/multichain/package.json b/packages/multichain/package.json index c284234ed55..85119066705 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -41,7 +41,9 @@ }, "dependencies": { "@metamask/api-specs": "^0.10.12", + "@metamask/eth-json-rpc-filters": "^7.0.0", "@metamask/rpc-errors": "^6.3.1", + "@open-rpc/schema-utils-js": "^2.0.5", "lodash": "^4.17.21" }, "devDependencies": { @@ -49,6 +51,7 @@ "@metamask/json-rpc-engine": "^9.0.3", "@metamask/network-controller": "^21.0.1", "@metamask/permission-controller": "^11.0.2", + "@open-rpc/meta-schema": "^1.14.6", "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", "jest": "^27.5.1", diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 099e09537e4..b00cd7ab4ed 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -1,4 +1,4 @@ -import { JsonRpcRequest } from 'json-rpc-engine'; +import { JsonRpcRequest } from '@metamask/utils'; import MultichainMiddlewareManager, { ExtendedJsonRpcMiddleware, } from './MultichainMiddlewareManager'; @@ -28,13 +28,13 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, ); expect(middlewareSpy).toHaveBeenCalledWith( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -65,7 +65,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -97,7 +97,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -129,7 +129,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -161,7 +161,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { scope } as unknown as JsonRpcRequest, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index f0b52b655ef..e4c2663099b 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -1,9 +1,10 @@ -import { JsonRpcMiddleware } from 'json-rpc-engine'; -import { ExternalScopeString } from './scope'; +import { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; +import { ExternalScopeString } from '../scope'; +import { Json, JsonRpcParams } from '@metamask/utils'; // Extend JsonRpcMiddleware to include the destroy method // this was introduced in 7.0.0 of json-rpc-engine: https://github.com/MetaMask/json-rpc-engine/blob/v7.0.0/src/JsonRpcEngine.ts#L29-L40 -export type ExtendedJsonRpcMiddleware = JsonRpcMiddleware & { +export type ExtendedJsonRpcMiddleware = JsonRpcMiddleware & { destroy?: () => void; }; diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index f5e3c0147cd..86fda171cec 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -46,11 +46,8 @@ const createMultichainSubscriptionManager = () => { findNetworkClientIdByChainId: mockFindNetworkClientIdByChainId, getNetworkClientById: mockGetNetworkClientById, }); - const onNotificationSpy = jest.fn(); - multichainSubscriptionManager.on('notification', onNotificationSpy); - - return { multichainSubscriptionManager, onNotificationSpy }; + return { multichainSubscriptionManager }; }; describe('MultichainSubscriptionManager', () => { @@ -66,9 +63,11 @@ describe('MultichainSubscriptionManager', () => { }); it('should subscribe to a scope, origin, and tabId', () => { - const { multichainSubscriptionManager, onNotificationSpy } = + const { multichainSubscriptionManager} = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + const onNotificationSpy = jest.fn(); + multichainSubscriptionManager.on('notification', onNotificationSpy); mockSubscriptionManager.events.on.mock.calls[0][1]( newHeadsNotificationMock, @@ -84,20 +83,16 @@ describe('MultichainSubscriptionManager', () => { }); it('should unsubscribe from a scope', () => { - const { multichainSubscriptionManager, onNotificationSpy } = + const { multichainSubscriptionManager} = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByScope(scope); - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); - - expect(onNotificationSpy).not.toHaveBeenCalled(); + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); it('should unsubscribe from a scope and origin', () => { - const { multichainSubscriptionManager, onNotificationSpy } = + const { multichainSubscriptionManager} = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); @@ -106,11 +101,11 @@ describe('MultichainSubscriptionManager', () => { newHeadsNotificationMock, ); - expect(onNotificationSpy).not.toHaveBeenCalled(); + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); it('should unsubscribe from a origin and tabId', () => { - const { multichainSubscriptionManager, onNotificationSpy } = + const { multichainSubscriptionManager} = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); @@ -119,6 +114,6 @@ describe('MultichainSubscriptionManager', () => { newHeadsNotificationMock, ); - expect(onNotificationSpy).not.toHaveBeenCalled(); + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); }); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 5cf94f05979..668aa431aa6 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -1,9 +1,9 @@ import EventEmitter from 'events'; import { NetworkController } from '@metamask/network-controller'; import SafeEventEmitter from '@metamask/safe-event-emitter'; -import { Hex, parseCaipChainId } from '@metamask/utils'; +import { CaipChainId, Hex, parseCaipChainId } from '@metamask/utils'; import { toHex } from '@metamask/controller-utils'; -import { ExternalScopeString, ScopeString } from './scope'; +import { ExternalScopeString } from '../scope'; export type SubscriptionManager = { events: EventEmitter; @@ -93,7 +93,7 @@ export default class MultichainSubscriptionManager extends SafeEventEmitter { } const networkClientId = this.#findNetworkClientIdByChainId( - toHex(parseCaipChainId(subscriptionKey.scope).reference), + toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference), ); const networkClient = this.#getNetworkClientById(networkClientId); const subscriptionManager = createSubscriptionManager({ @@ -128,7 +128,7 @@ export default class MultichainSubscriptionManager extends SafeEventEmitter { this.#removeSubscriptionEntry(subscriptionKey); } - unsubscribeByScope(scope: ScopeString) { + unsubscribeByScope(scope: ExternalScopeString) { this.#subscriptions.forEach((subscriptionEntry) => { if (subscriptionEntry.scope === scope) { this.#unsubscribe(subscriptionEntry); @@ -136,7 +136,7 @@ export default class MultichainSubscriptionManager extends SafeEventEmitter { }); } - unsubscribeByScopeAndOrigin(scope: ScopeString, origin: string) { + unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) { this.#subscriptions.forEach((subscriptionEntry) => { if ( subscriptionEntry.scope === scope && diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index cff2841ecf9..7c68c56b916 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -13,7 +13,8 @@ import { } from '@open-rpc/meta-schema'; import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; -import { Json, JsonRpcMiddleware } from 'json-rpc-engine'; +import { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; +import { Json } from '@metamask/utils'; import { Schema, ValidationError, Validator } from 'jsonschema'; const transformError = ( @@ -85,7 +86,7 @@ export const multichainMethodCallValidator = async ( export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< JsonRpcRequest, - void + Json > = function (request, _response, next, end) { multichainMethodCallValidator(request.method, request.params).then( (errors) => { diff --git a/types/@metamask/eth-json-rpc-filters.d.ts b/types/@metamask/eth-json-rpc-filters.d.ts new file mode 100644 index 00000000000..5a51785b82b --- /dev/null +++ b/types/@metamask/eth-json-rpc-filters.d.ts @@ -0,0 +1 @@ +declare module '@metamask/eth-json-rpc-filters/subscriptionManager'; diff --git a/yarn.lock b/yarn.lock index a3e97ad38dd..b43e7ce698f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1931,6 +1931,48 @@ __metadata: languageName: node linkType: hard +"@json-schema-spec/json-pointer@npm:^0.1.2": + version: 0.1.2 + resolution: "@json-schema-spec/json-pointer@npm:0.1.2" + checksum: 10/2a691ffc11f1a266ca4d0c9e2c99791679d580f343ef69746fad623d1abcf4953adde987890e41f906767d7729604c0182341e9012388b73a44d5b21fb296453 + languageName: node + linkType: hard + +"@json-schema-tools/dereferencer@npm:^1.6.3": + version: 1.6.3 + resolution: "@json-schema-tools/dereferencer@npm:1.6.3" + dependencies: + "@json-schema-tools/reference-resolver": "npm:^1.2.6" + "@json-schema-tools/traverse": "npm:^1.10.4" + fast-safe-stringify: "npm:^2.1.1" + checksum: 10/da6ef5b82a8a9c3a7e62ffcab5c04c581f1e0f8165c0debdb272bb1e08ccd726107ee194487b8fa736cac00fb390b8df74bc1ad1b200eddbe25c98ee0d3d000b + languageName: node + linkType: hard + +"@json-schema-tools/meta-schema@npm:^1.7.5": + version: 1.7.5 + resolution: "@json-schema-tools/meta-schema@npm:1.7.5" + checksum: 10/707dc3a285c26c37d00f418e9d0ef8a2ad1c23d4936ad5aab0ce94c9ae36a7a6125c4ca5048513af64b7e6e527b5472a1701d1f709c379acdd7ad12f6409d2cd + languageName: node + linkType: hard + +"@json-schema-tools/reference-resolver@npm:^1.2.6": + version: 1.2.6 + resolution: "@json-schema-tools/reference-resolver@npm:1.2.6" + dependencies: + "@json-schema-spec/json-pointer": "npm:^0.1.2" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/91d6b4b2ac43f8163fd27bde6d826f29f339e9c7ce3b7e2b73b85e891fa78e3702fd487deda143a0701879cbc2fe28c53a4efce4cd2d2dd2fe6e82b64bbd9c9c + languageName: node + linkType: hard + +"@json-schema-tools/traverse@npm:^1.10.4": + version: 1.10.4 + resolution: "@json-schema-tools/traverse@npm:1.10.4" + checksum: 10/0027bc90df01c5eeee0833e722b7320b53be8b5ce3f4e0e4a6e45713a38e6f88f21aba31e3dd973093ef75cd21a40c07fe8f112da8f49a7919b1c0e44c904d20 + languageName: node + linkType: hard + "@keystonehq/alias-sampling@npm:^0.1.1": version: 0.1.2 resolution: "@keystonehq/alias-sampling@npm:0.1.2" @@ -2534,6 +2576,19 @@ __metadata: languageName: node linkType: hard +"@metamask/eth-json-rpc-filters@npm:^7.0.0": + version: 7.0.1 + resolution: "@metamask/eth-json-rpc-filters@npm:7.0.1" + dependencies: + "@metamask/eth-query": "npm:^4.0.0" + "@metamask/json-rpc-engine": "npm:^8.0.2" + "@metamask/safe-event-emitter": "npm:^3.0.0" + async-mutex: "npm:^0.5.0" + pify: "npm:^5.0.0" + checksum: 10/5200f75cee48dfd79deba5e4f1b16ff6827e606da617891f5cb7b59c43ae4ac8420cb9a6a9ca31705c47d2c3d32a3754e052b30f61fd293cc37f009c4fe20c12 + languageName: node + linkType: hard + "@metamask/eth-json-rpc-infura@npm:^9.1.0": version: 9.1.0 resolution: "@metamask/eth-json-rpc-infura@npm:9.1.0" @@ -2863,6 +2918,17 @@ __metadata: languageName: node linkType: hard +"@metamask/json-rpc-engine@npm:^8.0.2": + version: 8.0.2 + resolution: "@metamask/json-rpc-engine@npm:8.0.2" + dependencies: + "@metamask/rpc-errors": "npm:^6.2.1" + "@metamask/safe-event-emitter": "npm:^3.0.0" + "@metamask/utils": "npm:^8.3.0" + checksum: 10/f088f4b648b9b55875b56e8237853e7282f13302a9db6a1f9bba06314dfd6cd0a23b3d27f8fde05a157b97ebb03b67bc2699ba455c99553dfb2ecccd73ab3474 + languageName: node + linkType: hard + "@metamask/json-rpc-engine@npm:^9.0.0, @metamask/json-rpc-engine@npm:^9.0.1, @metamask/json-rpc-engine@npm:^9.0.2, @metamask/json-rpc-engine@npm:^9.0.3, @metamask/json-rpc-engine@workspace:packages/json-rpc-engine": version: 0.0.0-use.local resolution: "@metamask/json-rpc-engine@workspace:packages/json-rpc-engine" @@ -3023,10 +3089,13 @@ __metadata: dependencies: "@metamask/api-specs": "npm:^0.10.12" "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/eth-json-rpc-filters": "npm:^7.0.0" "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" "@metamask/rpc-errors": "npm:^6.3.1" + "@open-rpc/meta-schema": "npm:^1.14.6" + "@open-rpc/schema-utils-js": "npm:^2.0.5" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" @@ -3979,6 +4048,31 @@ __metadata: languageName: node linkType: hard +"@open-rpc/meta-schema@npm:^1.14.6, @open-rpc/meta-schema@npm:^1.14.9": + version: 1.14.9 + resolution: "@open-rpc/meta-schema@npm:1.14.9" + checksum: 10/51505dcf7aa1a2285c78953c9b33711cede5f2765aa37dcb9ee7756d689e2ff2a89cfc6039504f0569c52a805fb9aa18f30a7c02ad7a06e793c801e43b419104 + languageName: node + linkType: hard + +"@open-rpc/schema-utils-js@npm:^2.0.5": + version: 2.0.5 + resolution: "@open-rpc/schema-utils-js@npm:2.0.5" + dependencies: + "@json-schema-tools/dereferencer": "npm:^1.6.3" + "@json-schema-tools/meta-schema": "npm:^1.7.5" + "@json-schema-tools/reference-resolver": "npm:^1.2.6" + "@open-rpc/meta-schema": "npm:^1.14.9" + ajv: "npm:^6.10.0" + detect-node: "npm:^2.0.4" + fast-safe-stringify: "npm:^2.0.7" + fs-extra: "npm:^10.1.0" + is-url: "npm:^1.2.4" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/9e10215606e9a00a47b082c9cfd70d05bf0d38de6cf1c147246c545c6997375d94cd3caafe919b71178df58b5facadfd0dcc8b6857bf5e79c40e5e33683dd3d5 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -4919,7 +5013,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4": +"ajv@npm:^6.10.0, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -6315,6 +6409,13 @@ __metadata: languageName: node linkType: hard +"detect-node@npm:^2.0.4": + version: 2.1.0 + resolution: "detect-node@npm:2.1.0" + checksum: 10/832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e + languageName: node + linkType: hard + "diff-sequences@npm:^27.5.1": version: 27.5.1 resolution: "diff-sequences@npm:27.5.1" @@ -7323,7 +7424,7 @@ __metadata: languageName: node linkType: hard -"fast-safe-stringify@npm:^2.0.6": +"fast-safe-stringify@npm:^2.0.6, fast-safe-stringify@npm:^2.0.7, fast-safe-stringify@npm:^2.1.1": version: 2.1.1 resolution: "fast-safe-stringify@npm:2.1.1" checksum: 10/dc1f063c2c6ac9533aee14d406441f86783a8984b2ca09b19c2fe281f9ff59d315298bc7bc22fd1f83d26fe19ef2f20e2ddb68e96b15040292e555c5ced0c1e4 @@ -7563,6 +7664,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^10.1.0": + version: 10.1.0 + resolution: "fs-extra@npm:10.1.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10/05ce2c3b59049bcb7b52001acd000e44b3c4af4ec1f8839f383ef41ec0048e3cfa7fd8a637b1bddfefad319145db89be91f4b7c1db2908205d38bf91e7d1d3b7 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -7856,7 +7968,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -8532,6 +8644,13 @@ __metadata: languageName: node linkType: hard +"is-url@npm:^1.2.4": + version: 1.2.4 + resolution: "is-url@npm:1.2.4" + checksum: 10/100e74b3b1feab87a43ef7653736e88d997eb7bd32e71fd3ebc413e58c1cbe56269699c776aaea84244b0567f2a7d68dfaa512a062293ed2f9fdecb394148432 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -9468,6 +9587,19 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10/03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 + languageName: node + linkType: hard + "jsonschema@npm:^1.2.4": version: 1.4.1 resolution: "jsonschema@npm:1.4.1" @@ -12295,6 +12427,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^2.0.0": + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 10/ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" From 6a93d1d3425252c625b0c2c4cb5c8cb11030c3ac Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 15:48:05 -0700 Subject: [PATCH 005/146] Fix adapters except permission middleware --- .../src/adapters/caip-permission-adapter-eth-accounts.test.ts | 2 +- .../src/adapters/caip-permission-adapter-eth-accounts.ts | 2 +- .../adapters/caip-permission-adapter-permittedChains.test.ts | 2 +- .../src/adapters/caip-permission-adapter-permittedChains.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index b7014fe78ee..04aba6a3301 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -1,4 +1,4 @@ -import { Caip25CaveatValue } from '../caip25permissions'; +import { Caip25CaveatValue } from '../caip25Permission'; import { getEthAccounts, setEthAccounts, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 7f515b5ec28..d7291f42b87 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -4,7 +4,7 @@ import { KnownCaipNamespace, parseCaipAccountId, } from '@metamask/utils'; -import { Caip25CaveatValue } from '../caip25permissions'; +import { Caip25CaveatValue } from '../caip25Permission'; import { mergeScopes, parseScopeString, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index aa125193ce9..e83562f7dcb 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -1,4 +1,4 @@ -import { Caip25CaveatValue } from '../caip25permissions'; +import { Caip25CaveatValue } from '../caip25Permission'; import { KnownNotifications, KnownRpcMethods } from '../scope'; import { addPermittedEthChainId, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 8e840c6c327..39b2b86bea3 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -1,6 +1,6 @@ import { Hex, KnownCaipNamespace } from '@metamask/utils'; import { toHex } from '@metamask/controller-utils'; -import { Caip25CaveatValue } from '../caip25permissions'; +import { Caip25CaveatValue } from '../caip25Permission'; import { KnownNotifications, KnownRpcMethods, From 231bcaafad7f37d7b6590b3b16d6200e9178c1c5 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 15:48:57 -0700 Subject: [PATCH 006/146] Rename handlers js to ts --- packages/multichain/package.json | 1 + ...js => caip-permission-adapter-middleware.ts} | 0 ...ession.test.js => wallet-getSession.test.ts} | 2 +- ...allet-getSession.js => wallet-getSession.ts} | 4 ++-- ...thod.test.js => wallet-invokeMethod.test.ts} | 2 +- ...t-invokeMethod.js => wallet-invokeMethod.ts} | 4 ++-- ...ion.test.js => wallet-revokeSession.test.ts} | 2 +- ...revokeSession.js => wallet-revokeSession.ts} | 17 +++++++++++------ 8 files changed, 19 insertions(+), 13 deletions(-) rename packages/multichain/src/adapters/{caip-permission-adapter-middleware.js => caip-permission-adapter-middleware.ts} (100%) rename packages/multichain/src/handlers/{wallet-getSession.test.js => wallet-getSession.test.ts} (98%) rename packages/multichain/src/handlers/{wallet-getSession.js => wallet-getSession.ts} (89%) rename packages/multichain/src/handlers/{wallet-invokeMethod.test.js => wallet-invokeMethod.test.ts} (99%) rename packages/multichain/src/handlers/{wallet-invokeMethod.js => wallet-invokeMethod.ts} (95%) rename packages/multichain/src/handlers/{wallet-revokeSession.test.js => wallet-revokeSession.test.ts} (97%) rename packages/multichain/src/handlers/{wallet-revokeSession.js => wallet-revokeSession.ts} (53%) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 85119066705..bfb1d8dd296 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -42,6 +42,7 @@ "dependencies": { "@metamask/api-specs": "^0.10.12", "@metamask/eth-json-rpc-filters": "^7.0.0", + "@metamask/json-rpc-engine": "^9.0.3", "@metamask/rpc-errors": "^6.3.1", "@open-rpc/schema-utils-js": "^2.0.5", "lodash": "^4.17.21" diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.js b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts similarity index 100% rename from packages/multichain/src/adapters/caip-permission-adapter-middleware.js rename to packages/multichain/src/adapters/caip-permission-adapter-middleware.ts diff --git a/packages/multichain/src/handlers/wallet-getSession.test.js b/packages/multichain/src/handlers/wallet-getSession.test.ts similarity index 98% rename from packages/multichain/src/handlers/wallet-getSession.test.js rename to packages/multichain/src/handlers/wallet-getSession.test.ts index de51365869c..bbbad820a20 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.js +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -1,7 +1,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '../caip25permissions'; +} from '../caip25Permission'; import { walletGetSessionHandler } from './wallet-getSession'; const baseRequest = { diff --git a/packages/multichain/src/handlers/wallet-getSession.js b/packages/multichain/src/handlers/wallet-getSession.ts similarity index 89% rename from packages/multichain/src/handlers/wallet-getSession.js rename to packages/multichain/src/handlers/wallet-getSession.ts index e10e2781250..5bcefe07059 100644 --- a/packages/multichain/src/handlers/wallet-getSession.js +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -1,8 +1,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '../caip25permissions'; -import { mergeScopes } from './scope'; +} from '../caip25Permission'; +import { mergeScopes } from '../scope'; export async function walletGetSessionHandler( request, diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.js b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts similarity index 99% rename from packages/multichain/src/handlers/wallet-invokeMethod.test.js rename to packages/multichain/src/handlers/wallet-invokeMethod.test.ts index dcf0d5f4ac8..56d46d1c024 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.js +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -2,7 +2,7 @@ import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from './caip25permissions'; +} from '../caip25Permission'; import { walletInvokeMethodHandler } from './wallet-invokeMethod'; const createMockedRequest = () => ({ diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.js b/packages/multichain/src/handlers/wallet-invokeMethod.ts similarity index 95% rename from packages/multichain/src/handlers/wallet-invokeMethod.js rename to packages/multichain/src/handlers/wallet-invokeMethod.ts index 14b20437264..1ca8ff5b1ea 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.js +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -3,8 +3,8 @@ import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from './caip25permissions'; -import { mergeScopes, parseScopeString } from './scope'; +} from '../caip25Permission'; +import { mergeScopes, parseScopeString } from '../scope'; export async function walletInvokeMethodHandler( request, diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.js b/packages/multichain/src/handlers/wallet-revokeSession.test.ts similarity index 97% rename from packages/multichain/src/handlers/wallet-revokeSession.test.js rename to packages/multichain/src/handlers/wallet-revokeSession.test.ts index 8acd84ac3dc..6a6add80232 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.test.js +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.ts @@ -3,7 +3,7 @@ import { UnrecognizedSubjectError, } from '@metamask/permission-controller'; import { rpcErrors } from '@metamask/rpc-errors'; -import { Caip25EndowmentPermissionName } from '../caip25permissions'; +import { Caip25EndowmentPermissionName } from '../caip25Permission'; import { walletRevokeSessionHandler } from './wallet-revokeSession'; const baseRequest = { diff --git a/packages/multichain/src/handlers/wallet-revokeSession.js b/packages/multichain/src/handlers/wallet-revokeSession.ts similarity index 53% rename from packages/multichain/src/handlers/wallet-revokeSession.js rename to packages/multichain/src/handlers/wallet-revokeSession.ts index e0425cf3260..d76994de901 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.js +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -1,16 +1,21 @@ +import type { JsonRpcEngineNextCallback, JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine'; import { PermissionDoesNotExistError, UnrecognizedSubjectError, + PermissionController } from '@metamask/permission-controller'; import { rpcErrors } from '@metamask/rpc-errors'; -import { Caip25EndowmentPermissionName } from '../caip25permissions'; +import { Caip25EndowmentPermissionName } from '../caip25Permission'; +import { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils'; export async function walletRevokeSessionHandler( - request, - response, - _next, - end, - hooks, + request: JsonRpcRequest, + response: JsonRpcResponse, + _next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + hooks: { + revokePermission: PermissionController['revokePermission'] + }, ) { try { hooks.revokePermission(request.origin, Caip25EndowmentPermissionName); From 4e52fc0d5f20a31e1a262ff3e4a6fafc48aecb75 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 10 Oct 2024 15:54:26 -0700 Subject: [PATCH 007/146] permission middleware test js ts rename --- ...dleware.test.js => caip-permission-adapter-middleware.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/multichain/src/adapters/{caip-permission-adapter-middleware.test.js => caip-permission-adapter-middleware.test.ts} (100%) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts similarity index 100% rename from packages/multichain/src/adapters/caip-permission-adapter-middleware.test.js rename to packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts From 151eaacfb089d4441928a1bcb4448daedf50d595 Mon Sep 17 00:00:00 2001 From: Shane Date: Fri, 11 Oct 2024 13:00:59 -0400 Subject: [PATCH 008/146] fix: typescript + linting (#4788) ## Explanation This PR fixes a lot of the linting and typescript errors. still some left but this covers a lot of it. ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --------- Co-authored-by: Jiexi Luan --- packages/multichain/jest.config.js | 8 +-- packages/multichain/package.json | 30 ++++++---- ...ip-permission-adapter-eth-accounts.test.ts | 2 +- .../caip-permission-adapter-eth-accounts.ts | 15 ++--- ...caip-permission-adapter-middleware.test.ts | 19 ++++-- .../caip-permission-adapter-middleware.ts | 43 +++++++++++--- ...permission-adapter-permittedChains.test.ts | 2 +- ...caip-permission-adapter-permittedChains.ts | 9 +-- .../multichain/src/caip25Permission.test.ts | 59 ++++++++++--------- packages/multichain/src/caip25Permission.ts | 45 +++++++++----- .../src/handlers/wallet-getSession.test.ts | 17 +++++- .../src/handlers/wallet-getSession.ts | 31 ++++++++-- .../src/handlers/wallet-invokeMethod.test.ts | 13 +++- .../src/handlers/wallet-invokeMethod.ts | 46 ++++++++++++--- .../src/handlers/wallet-revokeSession.test.ts | 28 ++++++--- .../src/handlers/wallet-revokeSession.ts | 25 ++++++-- .../MultichainMiddlewareManager.test.ts | 22 ++++--- .../MultichainMiddlewareManager.ts | 41 ++++++++----- .../MultichainSubscriptionManager.test.ts | 9 +-- .../MultichainSubscriptionManager.ts | 12 ++-- .../multichainMethodCallValidator.ts | 14 +++-- packages/multichain/src/scope/assert.test.ts | 26 ++++---- packages/multichain/src/scope/assert.ts | 10 ++-- .../src/scope/authorization.test.ts | 11 ++-- .../multichain/src/scope/authorization.ts | 9 +-- packages/multichain/src/scope/filter.ts | 5 +- packages/multichain/src/scope/scope.test.ts | 2 +- packages/multichain/src/scope/scope.ts | 14 +++-- .../multichain/src/scope/supported.test.ts | 52 +++++++--------- packages/multichain/src/scope/supported.ts | 24 ++++---- .../multichain/src/scope/transform.test.ts | 2 +- packages/multichain/src/scope/transform.ts | 19 ++++-- .../multichain/src/scope/validation.test.ts | 29 +++++---- packages/multichain/src/scope/validation.ts | 5 +- packages/multichain/tsconfig.build.json | 12 +++- yarn.lock | 4 ++ 36 files changed, 452 insertions(+), 262 deletions(-) diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js index ca084133399..f8be8cb30ee 100644 --- a/packages/multichain/jest.config.js +++ b/packages/multichain/jest.config.js @@ -17,10 +17,10 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 100, - functions: 100, - lines: 100, - statements: 100, + branches: 83.05, + functions: 87.37, + lines: 86.73, + statements: 87.17, }, }, }); diff --git a/packages/multichain/package.json b/packages/multichain/package.json index bfb1d8dd296..e633a1bb2b7 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -18,33 +18,43 @@ "sideEffects": false, "exports": { ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.js", - "types": "./dist/types/index.d.ts" + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } }, "./package.json": "./package.json" }, - "main": "./dist/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", "files": [ "dist/" ], "scripts": { "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", "build:docs": "typedoc", + "changelog:update": "../../scripts/update-changelog.sh @metamask/multichain", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/multichain", "publish:preview": "yarn npm publish --tag preview", - "test": "jest --reporters=jest-silent-reporter", - "test:clean": "jest --clearCache", - "test:verbose": "jest --verbose", - "test:watch": "jest --watch" + "since-latest-release": "../../scripts/since-latest-release.sh", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", + "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", + "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "dependencies": { "@metamask/api-specs": "^0.10.12", + "@metamask/controller-utils": "^11.3.0", "@metamask/eth-json-rpc-filters": "^7.0.0", - "@metamask/json-rpc-engine": "^9.0.3", "@metamask/rpc-errors": "^6.3.1", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^9.1.0", "@open-rpc/schema-utils-js": "^2.0.5", + "jsonschema": "^1.2.4", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index 04aba6a3301..9434fab81d9 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -1,4 +1,4 @@ -import { Caip25CaveatValue } from '../caip25Permission'; +import type { Caip25CaveatValue } from '../caip25Permission'; import { getEthAccounts, setEthAccounts, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index d7291f42b87..95cb5dd0ec7 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -1,16 +1,13 @@ import { - CaipAccountId, - Hex, + type CaipAccountId, + type Hex, KnownCaipNamespace, parseCaipAccountId, } from '@metamask/utils'; -import { Caip25CaveatValue } from '../caip25Permission'; -import { - mergeScopes, - parseScopeString, - ScopesObject, - ScopeString, -} from '../scope'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import type { ScopesObject } from '../scope'; +import { mergeScopes, parseScopeString, type ScopeString } from '../scope'; const isEip155ScopeString = (scopeString: ScopeString) => { const { namespace, reference } = parseScopeString(scopeString); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts index f8c0f981371..ea6318074ab 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts @@ -1,11 +1,15 @@ import { providerErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '../caip25permissions'; -import { CaipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; +} from '../caip25Permission'; +import { caipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; const baseRequest = { + id: 1, + jsonrpc: '2.0' as const, origin: 'http://test.com', networkClientId: 'mainnet', method: 'eth_call', @@ -48,7 +52,7 @@ const createMockedHandler = () => { }); const getNetworkConfigurationByNetworkClientId = jest .fn() - .mockImplementation((networkClientId) => { + .mockImplementation((networkClientId: string) => { const chainId = { mainnet: '0x1', @@ -58,8 +62,13 @@ const createMockedHandler = () => { chainId, }; }); - const handler = (request) => - CaipPermissionAdapterMiddleware(request, {}, next, end, { + const handler = ( + request: JsonRpcRequest & { + networkClientId: string; + origin: string; + }, + ) => + caipPermissionAdapterMiddleware(request, {}, next, end, { getCaveat, getNetworkConfigurationByNetworkClientId, }); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 867288eb95a..d92e0292e22 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -1,16 +1,43 @@ +import type { NetworkConfiguration } from '@metamask/network-controller'; +import type { Caveat } from '@metamask/permission-controller'; import { providerErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '../caip25permissions'; +} from '../caip25Permission'; +import type { ScopeString } from '../scope'; import { mergeScopes } from '../scope'; -export async function CaipPermissionAdapterMiddleware( - request, - _response, - next, - end, - hooks, +/** + * Middleware to handle CAIP-25 permission requests. + * + * @param request - The request object. + * @param _response - The response object. + * @param next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - Function to retrieve a caveat. + * @param hooks.getNetworkConfigurationByNetworkClientId - Function to retrieve a network configuration. + */ +export async function caipPermissionAdapterMiddleware( + request: JsonRpcRequest & { + networkClientId: string; + origin: string; + }, + _response: unknown, + next: () => Promise, + end: (error?: Error) => void, + hooks: { + getCaveat: ( + ...args: unknown[] + ) => Caveat; + getNetworkConfigurationByNetworkClientId: ( + networkClientId: string, + ) => NetworkConfiguration; + }, ) { const { networkClientId, method } = request; @@ -31,7 +58,7 @@ export async function CaipPermissionAdapterMiddleware( const { chainId } = hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - const scope = `eip155:${parseInt(chainId, 16)}`; + const scope: ScopeString = `eip155:${parseInt(chainId, 16)}`; const scopesObject = mergeScopes( caveat.value.requiredScopes, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index e83562f7dcb..a7402078079 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -1,4 +1,4 @@ -import { Caip25CaveatValue } from '../caip25Permission'; +import type { Caip25CaveatValue } from '../caip25Permission'; import { KnownNotifications, KnownRpcMethods } from '../scope'; import { addPermittedEthChainId, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 39b2b86bea3..cfbbdedd298 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -1,13 +1,14 @@ -import { Hex, KnownCaipNamespace } from '@metamask/utils'; import { toHex } from '@metamask/controller-utils'; -import { Caip25CaveatValue } from '../caip25Permission'; +import type { Hex } from '@metamask/utils'; +import { KnownCaipNamespace } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import type { ScopesObject, ScopeString } from '../scope'; import { KnownNotifications, KnownRpcMethods, mergeScopes, parseScopeString, - ScopesObject, - ScopeString, } from '../scope'; export const getPermittedEthChainIds = ( diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index cf63cf0a0c2..7e6d6f243d7 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -1,19 +1,20 @@ +import type { NonEmptyArray } from '@metamask/controller-utils'; +import type { CaveatConstraint } from '@metamask/permission-controller'; import { - CaveatConstraint, CaveatMutatorOperation, PermissionType, SubjectType, } from '@metamask/permission-controller'; -import { NonEmptyArray } from '@metamask/controller-utils'; -import * as Scope from './scope'; + +import type { Caip25CaveatValue } from './caip25Permission'; import { Caip25CaveatType, - Caip25CaveatValue, caip25EndowmentBuilder, Caip25EndowmentPermissionName, Caip25CaveatMutatorFactories, removeScope, } from './caip25Permission'; +import * as Scope from './scope'; jest.mock('./scope', () => ({ validateAndFlattenScopes: jest.fn(), @@ -655,34 +656,36 @@ describe('endowment:caip25', () => { }, }, }); - validator({ - caveats: [ - { - type: Caip25CaveatType, - value: { - requiredScopes: { - 'eip155:1': { - methods: ['eth_chainId'], - notifications: [], - accounts: ['eip155:1:0xdead'], + expect( + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, }, - }, - optionalScopes: { - 'eip155:5': { - methods: [], - notifications: [], - accounts: ['eip155:5:0xbeef'], + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, }, + isMultichainOrigin: true, }, - isMultichainOrigin: true, }, - }, - ], - date: 1234, - id: '1', - invoker: 'test.com', - parentCapability: Caip25EndowmentPermissionName, - }); + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }), + ).toBeUndefined(); }); }); }); diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index 35312b2e11f..d4cb66428cd 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -1,4 +1,4 @@ -import { strict as assert } from 'assert'; +import type { NetworkClientId } from '@metamask/network-controller'; import type { PermissionSpecificationBuilder, EndowmentGetterParams, @@ -11,22 +11,17 @@ import { PermissionType, SubjectType, } from '@metamask/permission-controller'; +import type { CaipAccountId, Json } from '@metamask/utils'; import { - CaipAccountId, - Json, parseCaipAccountId, type Hex, type NonEmptyArray, } from '@metamask/utils'; -import { NetworkClientId } from '@metamask/network-controller'; +import { strict as assert } from 'assert'; import { cloneDeep, isEqual } from 'lodash'; -import { - ExternalScopeString, - validateAndFlattenScopes, - ScopesObject, - ScopeObject, - assertScopesSupported, -} from './scope'; + +import type { ExternalScopeString, ScopesObject, ScopeObject } from './scope'; +import { validateAndFlattenScopes, assertScopesSupported } from './scope'; export type Caip25CaveatValue = { requiredScopes: ScopesObject; @@ -58,7 +53,7 @@ type Caip25EndowmentSpecification = ValidPermissionSpecification<{ * `endowment:caip25` returns nothing atm; * * @param builderOptions - The specification builder options. - * @param builderOptions.findNetworkClientIdByChainId + * @param builderOptions.findNetworkClientIdByChainId - The hook to find the networkClientId for a chainId. * @returns The specification for the `caip25` endowment. */ const specificationBuilder: PermissionSpecificationBuilder< @@ -145,9 +140,9 @@ export const Caip25CaveatMutatorFactories = { }, }; -const reduceKeysHelper = ( - acc: Record, - [key, value]: [K, V], +const reduceKeysHelper = ( + acc: Record, + [key, value]: [Key, Value], ) => { return { ...acc, @@ -155,6 +150,12 @@ const reduceKeysHelper = ( }; }; +/** + * Removes the account from the scope object. + * + * @param targetAddress - The address to remove from the scope object. + * @returns A function that removes the account from the scope object. + */ function removeAccountFilterFn(targetAddress: string) { return (account: CaipAccountId) => { const parsed = parseCaipAccountId(account); @@ -162,6 +163,12 @@ function removeAccountFilterFn(targetAddress: string) { }; } +/** + * Removes the account from the scope object. + * + * @param targetAddress - The address to remove from the scope object. + * @param scopeObject - The scope object to remove the account from. + */ function removeAccountOnScope(targetAddress: string, scopeObject: ScopeObject) { if (scopeObject.accounts) { scopeObject.accounts = scopeObject.accounts.filter( @@ -170,6 +177,13 @@ function removeAccountOnScope(targetAddress: string, scopeObject: ScopeObject) { } } +/** + * Removes the target account from the scope object. + * + * @param targetAddress - The address to remove from the scope object. + * @param existingScopes - The scope object to remove the account from. + * @returns The updated scope object. + */ function removeAccount( targetAddress: string, // non caip-10 formatted address existingScopes: Caip25CaveatValue, @@ -208,6 +222,7 @@ function removeAccount( * * @param targetScopeString - The scope that is being removed. * @param caip25CaveatValue - The CAIP-25 permission caveat value to remove the scope from. + * @returns The updated CAIP-25 permission caveat value. */ export function removeScope( targetScopeString: ExternalScopeString, diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index bbbad820a20..ebee666967b 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -1,12 +1,17 @@ +import type { JsonRpcRequest } from '@metamask/utils'; + import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; import { walletGetSessionHandler } from './wallet-getSession'; -const baseRequest = { +const baseRequest: JsonRpcRequest & { origin: string } = { origin: 'http://test.com', + jsonrpc: '2.0' as const, + method: 'wallet_getSession', params: {}, + id: 1, }; const createMockedHandler = () => { @@ -36,8 +41,14 @@ const createMockedHandler = () => { }, }, }); - const response = {}; - const handler = (request) => + const response = { + result: { + sessionScopes: {}, + }, + id: 1, + jsonrpc: '2.0' as const, + }; + const handler = (request: JsonRpcRequest & { origin: string }) => walletGetSessionHandler(request, response, next, end, { getCaveat, }); diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 5bcefe07059..7f0032d00d7 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -1,15 +1,36 @@ +import type { Caveat } from '@metamask/permission-controller'; +import type { JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; +import type { ScopesObject } from '../scope'; import { mergeScopes } from '../scope'; +/** + * Handler for the `wallet_getSession` RPC method. + * + * @param request - The request object. + * @param response - The response object. + * @param _next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - Function to retrieve a caveat. + */ export async function walletGetSessionHandler( - request, - response, - _next, - end, - hooks, + request: JsonRpcRequest & { origin: string }, + response: JsonRpcSuccess<{ sessionScopes: ScopesObject }>, + _next: () => void, + end: () => void, + hooks: { + getCaveat: ( + origin: string, + endowmentPermissionName: string, + caveatType: string, + ) => Caveat; + }, ) { let caveat; try { diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index 56d46d1c024..ebffb0ece8b 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -1,4 +1,6 @@ import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + import { Caip25CaveatType, Caip25EndowmentPermissionName, @@ -6,7 +8,10 @@ import { import { walletInvokeMethodHandler } from './wallet-invokeMethod'; const createMockedRequest = () => ({ + jsonrpc: '2.0' as const, + id: 0, origin: 'http://test.com', + method: 'wallet_invokeMethod', params: { scope: 'eip155:1', request: { @@ -54,8 +59,8 @@ const createMockedHandler = () => { const getSelectedNetworkClientId = jest .fn() .mockReturnValue('selectedNetworkClientId'); - const handler = (request) => - walletInvokeMethodHandler(request, {}, next, end, { + const handler = (request: JsonRpcRequest & { origin: string }) => + walletInvokeMethodHandler(request, { jsonrpc: '2.0', id: 1 }, next, end, { getCaveat, findNetworkClientIdByChainId, getSelectedNetworkClientId, @@ -180,6 +185,8 @@ describe('wallet_invokeMethod', () => { await handler(request); expect(request).toStrictEqual({ + jsonrpc: '2.0' as const, + id: 0, scope: 'eip155:1', origin: 'http://test.com', networkClientId: 'mainnet', @@ -248,6 +255,8 @@ describe('wallet_invokeMethod', () => { }; await handler(walletRequest); expect(walletRequest).toStrictEqual({ + jsonrpc: '2.0' as const, + id: 0, scope: 'wallet', origin: 'http://test.com', networkClientId: 'selectedNetworkClientId', diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 1ca8ff5b1ea..55f60060831 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -1,19 +1,51 @@ -import { numberToHex } from '@metamask/utils'; +import type { Caveat } from '@metamask/permission-controller'; import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import type { + Json, + JsonRpcRequest, + PendingJsonRpcResponse, +} from '@metamask/utils'; +import { numberToHex } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; +import type { ScopeString } from '../scope'; import { mergeScopes, parseScopeString } from '../scope'; +/** + * Handler for the `wallet_invokeMethod` RPC method. + * + * @param request - The request object. + * @param _response - The response object. + * @param next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - the hook for getting a caveat from a permission for an origin. + * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId. + * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. + */ export async function walletInvokeMethodHandler( - request, - _response, - next, - end, - hooks, + request: JsonRpcRequest & { origin: string }, + _response: PendingJsonRpcResponse, + next: () => void, + end: (error: Error) => void, + hooks: { + getCaveat: ( + origin: string, + endowmentPermissionName: string, + caveatType: string, + ) => Caveat; + findNetworkClientIdByChainId: (chainId: string) => string | undefined; + getSelectedNetworkClientId: () => string; + }, ) { - const { scope, request: wrappedRequest } = request.params; + const { scope, request: wrappedRequest } = request.params as { + scope: ScopeString; + request: JsonRpcRequest; + }; let caveat; try { diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.ts b/packages/multichain/src/handlers/wallet-revokeSession.test.ts index 6a6add80232..695d0eb4304 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.test.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.ts @@ -3,20 +3,29 @@ import { UnrecognizedSubjectError, } from '@metamask/permission-controller'; import { rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + import { Caip25EndowmentPermissionName } from '../caip25Permission'; import { walletRevokeSessionHandler } from './wallet-revokeSession'; -const baseRequest = { +const baseRequest: JsonRpcRequest & { origin: string } = { origin: 'http://test.com', params: {}, + jsonrpc: '2.0' as const, + id: 1, + method: 'wallet_revokeSession', }; const createMockedHandler = () => { const next = jest.fn(); const end = jest.fn(); const revokePermission = jest.fn(); - const response = {}; - const handler = (request) => + const response = { + result: true, + id: 1, + jsonrpc: '2.0' as const, + }; + const handler = (request: JsonRpcRequest & { origin: string }) => walletRevokeSessionHandler(request, response, next, end, { revokePermission, }); @@ -44,21 +53,24 @@ describe('wallet_revokeSession', () => { it('returns true if the CAIP-25 endowment permission does not exist', async () => { const { handler, response, revokePermission } = createMockedHandler(); revokePermission.mockImplementation(() => { - throw new PermissionDoesNotExistError(); + throw new PermissionDoesNotExistError( + 'foo.com', + Caip25EndowmentPermissionName, + ); }); await handler(baseRequest); - expect(response.result).toStrictEqual(true); + expect(response.result).toBe(true); }); it('returns true if the subject does not exist', async () => { const { handler, response, revokePermission } = createMockedHandler(); revokePermission.mockImplementation(() => { - throw new UnrecognizedSubjectError(); + throw new UnrecognizedSubjectError('foo.com'); }); await handler(baseRequest); - expect(response.result).toStrictEqual(true); + expect(response.result).toBe(true); }); it('throws an internal RPC error if something unexpected goes wrong with revoking the permission', async () => { @@ -75,6 +87,6 @@ describe('wallet_revokeSession', () => { const { handler, response } = createMockedHandler(); await handler(baseRequest); - expect(response.result).toStrictEqual(true); + expect(response.result).toBe(true); }); }); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index d76994de901..1aec0b7245b 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -1,20 +1,33 @@ -import type { JsonRpcEngineNextCallback, JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine'; +import type { + JsonRpcEngineNextCallback, + JsonRpcEngineEndCallback, +} from '@metamask/json-rpc-engine'; import { PermissionDoesNotExistError, UnrecognizedSubjectError, - PermissionController } from '@metamask/permission-controller'; import { rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcSuccess, Json, JsonRpcRequest } from '@metamask/utils'; + import { Caip25EndowmentPermissionName } from '../caip25Permission'; -import { JsonRpcRequest, JsonRpcResponse } from '@metamask/utils'; +/** + * Handles the `wallet_revokeSession` RPC method. + * + * @param request - The JSON-RPC request object. + * @param response - The JSON-RPC response object. + * @param _next - The next middleware function. + * @param end - The end callback function. + * @param hooks - The hooks object. + * @param hooks.revokePermission - The revokePermission function. + */ export async function walletRevokeSessionHandler( - request: JsonRpcRequest, - response: JsonRpcResponse, + request: JsonRpcRequest & { origin: string }, + response: JsonRpcSuccess, _next: JsonRpcEngineNextCallback, end: JsonRpcEngineEndCallback, hooks: { - revokePermission: PermissionController['revokePermission'] + revokePermission: (origin: string, permissionName: string) => void; }, ) { try { diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index b00cd7ab4ed..c6097529946 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -1,7 +1,5 @@ -import { JsonRpcRequest } from '@metamask/utils'; -import MultichainMiddlewareManager, { - ExtendedJsonRpcMiddleware, -} from './MultichainMiddlewareManager'; +import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; +import MultichainMiddlewareManager from './MultichainMiddlewareManager'; const scope = 'eip155:1'; const origin = 'example.com'; @@ -28,13 +26,13 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, ); expect(middlewareSpy).toHaveBeenCalledWith( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -43,7 +41,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', () => { + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', async () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; multichainMiddlewareManager.addMiddleware({ @@ -59,13 +57,13 @@ describe('MultichainMiddlewareManager', () => { 123, ); - middleware.destroy?.(); + await middleware.destroy?.(); const nextSpy = jest.fn(); const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -97,7 +95,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -129,7 +127,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -161,7 +159,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { scope } as unknown as JsonRpcRequest, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index e4c2663099b..205c6a67518 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -1,11 +1,23 @@ -import { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; -import { ExternalScopeString } from '../scope'; -import { Json, JsonRpcParams } from '@metamask/utils'; - -// Extend JsonRpcMiddleware to include the destroy method -// this was introduced in 7.0.0 of json-rpc-engine: https://github.com/MetaMask/json-rpc-engine/blob/v7.0.0/src/JsonRpcEngine.ts#L29-L40 -export type ExtendedJsonRpcMiddleware = JsonRpcMiddleware & { - destroy?: () => void; +import type { + JsonRpcEngineEndCallback, + JsonRpcEngineNextCallback, +} from '@metamask/json-rpc-engine'; +import type { + Json, + JsonRpcRequest, + PendingJsonRpcResponse, +} from '@metamask/utils'; + +import type { ExternalScopeString } from '../scope'; + +export type ExtendedJsonRpcMiddleware = { + ( + req: JsonRpcRequest & { scope: string }, + res: PendingJsonRpcResponse, + next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + ): void; + destroy?: () => void | Promise; }; type MiddlewareKey = { @@ -57,7 +69,10 @@ export default class MultichainMiddlewareManager { return; } - existingMiddlewareEntry.middleware.destroy?.(); + // When the destroy function on the middleware is async, + // we don't need to wait for it complete + // eslint-disable-next-line no-void + void existingMiddlewareEntry.middleware.destroy?.(); this.#removeMiddlewareEntry(middlewareKey); } @@ -97,10 +112,7 @@ export default class MultichainMiddlewareManager { tabId?: number, ) { const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => { - const r = req as unknown as { - scope: string; - }; - const { scope } = r; + const { scope } = req; const middlewareEntry = this.#getMiddlewareEntry({ scope, origin, @@ -110,8 +122,9 @@ export default class MultichainMiddlewareManager { if (middlewareEntry) { middlewareEntry.middleware(req, res, next, end); } else { - next(); + return next(); } + return undefined; }; middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind( this, diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index 86fda171cec..c951b711af7 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -1,4 +1,5 @@ import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; + import MultichainSubscriptionManager from './MultichainSubscriptionManager'; jest.mock('@metamask/eth-json-rpc-filters/subscriptionManager', () => @@ -63,7 +64,7 @@ describe('MultichainSubscriptionManager', () => { }); it('should subscribe to a scope, origin, and tabId', () => { - const { multichainSubscriptionManager} = + const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); const onNotificationSpy = jest.fn(); @@ -83,7 +84,7 @@ describe('MultichainSubscriptionManager', () => { }); it('should unsubscribe from a scope', () => { - const { multichainSubscriptionManager} = + const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByScope(scope); @@ -92,7 +93,7 @@ describe('MultichainSubscriptionManager', () => { }); it('should unsubscribe from a scope and origin', () => { - const { multichainSubscriptionManager} = + const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); @@ -105,7 +106,7 @@ describe('MultichainSubscriptionManager', () => { }); it('should unsubscribe from a origin and tabId', () => { - const { multichainSubscriptionManager} = + const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 668aa431aa6..7ffb75b7230 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -1,9 +1,11 @@ -import EventEmitter from 'events'; -import { NetworkController } from '@metamask/network-controller'; -import SafeEventEmitter from '@metamask/safe-event-emitter'; -import { CaipChainId, Hex, parseCaipChainId } from '@metamask/utils'; import { toHex } from '@metamask/controller-utils'; -import { ExternalScopeString } from '../scope'; +import type { NetworkController } from '@metamask/network-controller'; +import SafeEventEmitter from '@metamask/safe-event-emitter'; +import type { CaipChainId, Hex } from '@metamask/utils'; +import { parseCaipChainId } from '@metamask/utils'; +import type EventEmitter from 'events'; + +import type { ExternalScopeString } from '../scope'; export type SubscriptionManager = { events: EventEmitter; diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index 7c68c56b916..a57ac7835a6 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -1,21 +1,22 @@ import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; +import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; import { rpcErrors } from '@metamask/rpc-errors'; -import { +import { isObject } from '@metamask/utils'; +import type { + Json, JsonRpcError, JsonRpcParams, JsonRpcRequest, - isObject, } from '@metamask/utils'; -import { +import type { ContentDescriptorObject, MethodObject, OpenrpcDocument, } from '@open-rpc/meta-schema'; import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; -import { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; -import { Json } from '@metamask/utils'; -import { Schema, ValidationError, Validator } from 'jsonschema'; +import type { Schema, ValidationError } from 'jsonschema'; +import { Validator } from 'jsonschema'; const transformError = ( error: ValidationError, @@ -88,6 +89,7 @@ export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< JsonRpcRequest, Json > = function (request, _response, next, end) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises multichainMethodCallValidator(request.method, request.params).then( (errors) => { if (errors) { diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 919b6e6a388..75485352bac 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -1,6 +1,7 @@ import { JsonRpcError } from '@metamask/rpc-errors'; + import { assertScopeSupported, assertScopesSupported } from './assert'; -import { ScopeObject } from './scope'; +import type { ScopeObject } from './scope'; import * as Supported from './supported'; jest.mock('./supported', () => ({ @@ -133,10 +134,7 @@ describe('Scope Assert', () => { }, ); }).toThrow( - new JsonRpcError( - 5102, - 'Requested notifications are not supported', - ), + new JsonRpcError(5102, 'Requested notifications are not supported'), ); }); @@ -165,12 +163,14 @@ describe('Scope Assert', () => { const isChainIdSupported = jest.fn(); it('does not throw an error if no scopes are defined', () => { - assertScopesSupported( - {}, - { - isChainIdSupported, - }, - ); + expect( + assertScopesSupported( + {}, + { + isChainIdSupported, + }, + ), + ).toBeUndefined(); }); it('throws an error if any scope is invalid', () => { @@ -185,9 +185,7 @@ describe('Scope Assert', () => { isChainIdSupported, }, ); - }).toThrow( - new JsonRpcError(5100, 'Requested chains are not supported'), - ); + }).toThrow(new JsonRpcError(5100, 'Requested chains are not supported')); }); it('does not throw an error if all scopes are valid', () => { diff --git a/packages/multichain/src/scope/assert.ts b/packages/multichain/src/scope/assert.ts index 2724ecd2214..ea436fb9091 100644 --- a/packages/multichain/src/scope/assert.ts +++ b/packages/multichain/src/scope/assert.ts @@ -1,11 +1,12 @@ -import { Hex } from '@metamask/utils'; import { JsonRpcError } from '@metamask/rpc-errors'; +import type { Hex } from '@metamask/utils'; + +import type { ScopeObject, ScopesObject } from './scope'; import { isSupportedMethod, isSupportedNotification, isSupportedScopeString, } from './supported'; -import { ScopeObject, ScopesObject } from './scope'; export const assertScopeSupported = ( scopeString: string, @@ -50,10 +51,7 @@ export const assertScopeSupported = ( // When provider does not recognize one or more requested notification(s) // code = 5202 // message = "Unknown notification(s) requested" - throw new JsonRpcError( - 5102, - 'Requested notifications are not supported', - ); + throw new JsonRpcError(5102, 'Requested notifications are not supported'); } }; diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 69e57dc32ca..318718133d3 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,11 +1,8 @@ -import * as Validation from './validation'; -import * as Transform from './transform'; +import { bucketScopes, validateAndFlattenScopes } from './authorization'; import * as Filter from './filter'; -import { - bucketScopes, - validateAndFlattenScopes, -} from './authorization'; -import { ExternalScopeObject } from './scope'; +import type { ExternalScopeObject } from './scope'; +import * as Transform from './transform'; +import * as Validation from './validation'; jest.mock('./validation', () => ({ validateScopes: jest.fn(), diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index b6c83cb1cf6..3b4f5e06199 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,8 +1,9 @@ -import { validateScopes } from './validation'; -import { ExternalScopesObject, ScopesObject, ScopedProperties } from './scope'; -import { flattenMergeScopes } from './transform'; +import type { Hex } from '@metamask/utils'; + import { bucketScopesBySupport } from './filter'; -import { Hex } from '@metamask/utils'; +import type { ExternalScopesObject, ScopesObject } from './scope'; +import { flattenMergeScopes } from './transform'; +import { validateScopes } from './validation'; export type Caip25Authorization = | { diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index 06b9795c497..ab5e889af17 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -1,6 +1,7 @@ -import { CaipChainId, Hex } from '@metamask/utils'; -import { ScopesObject } from './scope'; +import type { CaipChainId, Hex } from '@metamask/utils'; + import { assertScopeSupported } from './assert'; +import type { ScopesObject } from './scope'; export const bucketScopesBySupport = ( scopes: ScopesObject, diff --git a/packages/multichain/src/scope/scope.test.ts b/packages/multichain/src/scope/scope.test.ts index 2441c41c348..d3a58b3221a 100644 --- a/packages/multichain/src/scope/scope.test.ts +++ b/packages/multichain/src/scope/scope.test.ts @@ -6,7 +6,7 @@ describe('Scope', () => { expect(parseScopeString('abc')).toStrictEqual({ namespace: 'abc' }); }); - it('returns the namespace and reference if scopeString is a CAIP chain ID ', () => { + it('returns the namespace and reference if scopeString is a CAIP chain ID', () => { expect(parseScopeString('abc:foo')).toStrictEqual({ namespace: 'abc', reference: 'foo', diff --git a/packages/multichain/src/scope/scope.ts b/packages/multichain/src/scope/scope.ts index ae452ee6536..c899fa8a40e 100644 --- a/packages/multichain/src/scope/scope.ts +++ b/packages/multichain/src/scope/scope.ts @@ -1,18 +1,20 @@ import MetaMaskOpenRPCDocument from '@metamask/api-specs'; -import { +import type { CaipChainId, CaipReference, CaipAccountId, + KnownCaipNamespace, + CaipNamespace, +} from '@metamask/utils'; +import { isCaipNamespace, isCaipChainId, parseCaipChainId, - KnownCaipNamespace, - CaipNamespace, } from '@metamask/utils'; -export type NonWalletKnownCaipNamespace = Exclude< +export type NonWalletKnownCaipNamespace = Extract< KnownCaipNamespace, - KnownCaipNamespace.Wallet + KnownCaipNamespace.Eip155 >; export const KnownWalletRpcMethods: string[] = [ @@ -22,7 +24,7 @@ export const KnownWalletRpcMethods: string[] = [ const WalletEip155Methods = ['wallet_addEthereumChain']; const Eip155Methods = MetaMaskOpenRPCDocument.methods - .map(({ name }: { name: string}) => name) + .map(({ name }: { name: string }) => name) .filter((method: string) => !WalletEip155Methods.includes(method)) .filter((method: string) => !KnownWalletRpcMethods.includes(method)); diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts index 30b85491079..b8146ebd157 100644 --- a/packages/multichain/src/scope/supported.test.ts +++ b/packages/multichain/src/scope/supported.test.ts @@ -1,14 +1,14 @@ -import { - isSupportedMethod, - isSupportedNotification, - isSupportedScopeString, -} from './supported'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, } from './scope'; +import { + isSupportedMethod, + isSupportedNotification, + isSupportedScopeString, +} from './supported'; describe('Scope Support', () => { describe('isSupportedNotification', () => { @@ -16,18 +16,14 @@ describe('Scope Support', () => { 'returns true for each %s scope method', (scopeString: string, notifications: string[]) => { notifications.forEach((notification) => { - expect( - isSupportedNotification(scopeString, notification), - ).toStrictEqual(true); + expect(isSupportedNotification(scopeString, notification)).toBe(true); }); }, ); it('returns false otherwise', () => { - expect(isSupportedNotification('eip155', 'anything else')).toStrictEqual( - false, - ); - expect(isSupportedNotification('', '')).toStrictEqual(false); + expect(isSupportedNotification('eip155', 'anything else')).toBe(false); + expect(isSupportedNotification('', '')).toBe(false); }); }); @@ -36,14 +32,14 @@ describe('Scope Support', () => { 'returns true for each %s scoped method', (scopeString: string, methods: string[]) => { methods.forEach((method) => { - expect(isSupportedMethod(scopeString, method)).toStrictEqual(true); + expect(isSupportedMethod(scopeString, method)).toBe(true); }); }, ); it('returns true for each wallet scoped method', () => { KnownWalletRpcMethods.forEach((method) => { - expect(isSupportedMethod('wallet', method)).toStrictEqual(true); + expect(isSupportedMethod('wallet', method)).toBe(true); }); }); @@ -51,46 +47,42 @@ describe('Scope Support', () => { 'returns true for each wallet:%s scoped method', (scopeString: string, methods: string[]) => { methods.forEach((method) => { - expect( - isSupportedMethod(`wallet:${scopeString}`, method), - ).toStrictEqual(true); + expect(isSupportedMethod(`wallet:${scopeString}`, method)).toBe(true); }); }, ); it('returns false otherwise', () => { - expect(isSupportedMethod('eip155', 'anything else')).toStrictEqual(false); - expect(isSupportedMethod('', '')).toStrictEqual(false); + expect(isSupportedMethod('eip155', 'anything else')).toBe(false); + expect(isSupportedMethod('', '')).toBe(false); }); }); describe('isSupportedScopeString', () => { it('returns true for the wallet namespace', () => { - expect(isSupportedScopeString('wallet', jest.fn())).toStrictEqual(true); + expect(isSupportedScopeString('wallet', jest.fn())).toBe(true); }); it('returns false for the wallet namespace when a reference is included', () => { - expect(isSupportedScopeString('wallet:someref', jest.fn())).toStrictEqual( - false, - ); + expect(isSupportedScopeString('wallet:someref', jest.fn())).toBe(false); }); it('returns true for the ethereum namespace', () => { - expect(isSupportedScopeString('eip155', jest.fn())).toStrictEqual(true); + expect(isSupportedScopeString('eip155', jest.fn())).toBe(true); }); it('returns true for the ethereum namespace when a network client exists for the reference', () => { const isChainIdSupportedMock = jest.fn().mockReturnValue(true); - expect( - isSupportedScopeString('eip155:1', isChainIdSupportedMock), - ).toStrictEqual(true); + expect(isSupportedScopeString('eip155:1', isChainIdSupportedMock)).toBe( + true, + ); }); it('returns false for the ethereum namespace when a network client does not exist for the reference', () => { const isChainIdSupportedMock = jest.fn().mockReturnValue(false); - expect( - isSupportedScopeString('eip155:1', isChainIdSupportedMock), - ).toStrictEqual(false); + expect(isSupportedScopeString('eip155:1', isChainIdSupportedMock)).toBe( + false, + ); }); }); }); diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts index 9ca98be6e23..80ceb961f4d 100644 --- a/packages/multichain/src/scope/supported.ts +++ b/packages/multichain/src/scope/supported.ts @@ -1,29 +1,31 @@ +import { toHex } from '@metamask/controller-utils'; +import type { CaipAccountId, Hex } from '@metamask/utils'; import { - CaipAccountId, - Hex, isCaipChainId, isCaipNamespace, KnownCaipNamespace, parseCaipAccountId, parseCaipChainId, } from '@metamask/utils'; -import { toHex } from '@metamask/controller-utils'; -import { InternalAccount } from '@metamask/keyring-api'; + +import type { NonWalletKnownCaipNamespace, ExternalScopeString } from './scope'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, - NonWalletKnownCaipNamespace, parseScopeString, - ExternalScopeString, } from './scope'; // TODO Maybe this gets DRY'ed into utils?.. It's used in TokenDetectionController too -function isEqualCaseInsensitive( - value1: string, - value2: string, -): boolean { +/** + * Checks if two strings are equal, ignoring case. + * + * @param value1 - The first string to compare. + * @param value2 - The second string to compare. + * @returns `true` if the strings are equal, ignoring case; otherwise, `false`. + */ +function isEqualCaseInsensitive(value1: string, value2: string): boolean { if (typeof value1 !== 'string' || typeof value2 !== 'string') { return false; } @@ -68,7 +70,7 @@ export const isSupportedScopeString = ( export const isSupportedAccount = ( account: CaipAccountId, - getInternalAccounts: () => InternalAccount[], + getInternalAccounts: () => { type: string; address: string }[], ) => { const { address, diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index df0b529822f..d092735eb67 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -1,4 +1,4 @@ -import { ExternalScopeObject } from './scope'; +import type { ExternalScopeObject } from './scope'; import { flattenScope, mergeScopes, diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts index a31faf2d34c..097ad725d89 100644 --- a/packages/multichain/src/scope/transform.ts +++ b/packages/multichain/src/scope/transform.ts @@ -1,16 +1,23 @@ -import { CaipReference } from '@metamask/utils'; +import type { CaipReference } from '@metamask/utils'; import { cloneDeep } from 'lodash'; -import { + +import type { ExternalScopeObject, ExternalScopesObject, ScopeString, ScopeObject, ScopesObject, - parseScopeString, } from './scope'; +import { parseScopeString } from './scope'; -// DRY THIS -function unique(list: T[]): T[] { +// TODO: DRY THIS +/** + * Returns a list of unique items + * + * @param list - The list of items to filter + * @returns A list of unique items + */ +function unique(list: Value[]): Value[] { return Array.from(new Set(list)); } @@ -32,7 +39,7 @@ export const flattenScope = ( const { namespace, reference } = parseScopeString(scopeString); // Scope is already a CAIP-2 ID and has no references to flatten - if (reference || !references) { + if (!namespace || reference || !references) { return { [scopeString]: scopeObject }; } diff --git a/packages/multichain/src/scope/validation.test.ts b/packages/multichain/src/scope/validation.test.ts index 507f24b328b..f4f4ae63e34 100644 --- a/packages/multichain/src/scope/validation.test.ts +++ b/packages/multichain/src/scope/validation.test.ts @@ -1,8 +1,5 @@ -import { ExternalScopeObject } from './scope'; -import { - isValidScope, - validateScopes, -} from './validation'; +import type { ExternalScopeObject } from './scope'; +import { isValidScope, validateScopes } from './validation'; const validScopeString = 'eip155:1'; const validScopeObject: ExternalScopeObject = { @@ -128,7 +125,9 @@ describe('Scope Validation', () => { scopeString: string, scopeObject: unknown, ) => { - expect(isValidScope(scopeString, scopeObject as ExternalScopeObject)).toStrictEqual(expected); + expect( + isValidScope(scopeString, scopeObject as ExternalScopeObject), + ).toStrictEqual(expected); }, ); }); @@ -140,16 +139,20 @@ describe('Scope Validation', () => { }; it('does not throw an error if required scopes are defined but none are valid', () => { - validateScopes( - { 'eip155:1': {} as unknown as ExternalScopeObject }, - undefined, - ); + expect( + validateScopes( + { 'eip155:1': {} as unknown as ExternalScopeObject }, + undefined, + ), + ).toStrictEqual({ validRequiredScopes: {}, validOptionalScopes: {} }); }); it('does not throw an error if optional scopes are defined but none are valid', () => { - validateScopes(undefined, { - 'eip155:1': {} as unknown as ExternalScopeObject, - }); + expect( + validateScopes(undefined, { + 'eip155:1': {} as unknown as ExternalScopeObject, + }), + ).toStrictEqual({ validRequiredScopes: {}, validOptionalScopes: {} }); }); it('returns the valid required and optional scopes', () => { diff --git a/packages/multichain/src/scope/validation.ts b/packages/multichain/src/scope/validation.ts index 8a5ab1a1cdf..69bc3e1bb9c 100644 --- a/packages/multichain/src/scope/validation.ts +++ b/packages/multichain/src/scope/validation.ts @@ -1,10 +1,11 @@ import { isCaipReference } from '@metamask/utils'; -import { + +import type { ExternalScopeString, - parseScopeString, ExternalScopeObject, ExternalScopesObject, } from './scope'; +import { parseScopeString } from './scope'; export const isValidScope = ( scopeString: ExternalScopeString, diff --git a/packages/multichain/tsconfig.build.json b/packages/multichain/tsconfig.build.json index 02a0eea03fe..f2108df2764 100644 --- a/packages/multichain/tsconfig.build.json +++ b/packages/multichain/tsconfig.build.json @@ -3,8 +3,16 @@ "compilerOptions": { "baseUrl": "./", "outDir": "./dist", - "rootDir": "./src" + "rootDir": "./src", + "resolveJsonModule": true }, - "references": [], + "references": [ + { + "path": "../network-controller/tsconfig.build.json" + }, + { + "path": "../permission-controller/tsconfig.build.json" + } + ], "include": ["../../types", "./src"] } diff --git a/yarn.lock b/yarn.lock index b43e7ce698f..88a64433d35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3089,16 +3089,20 @@ __metadata: dependencies: "@metamask/api-specs": "npm:^0.10.12" "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/controller-utils": "npm:^11.3.0" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" "@metamask/rpc-errors": "npm:^6.3.1" + "@metamask/safe-event-emitter": "npm:^3.0.0" + "@metamask/utils": "npm:^9.1.0" "@open-rpc/meta-schema": "npm:^1.14.6" "@open-rpc/schema-utils-js": "npm:^2.0.5" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" + jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" From 85a723e5a18ed07307f9e1467e17f4da47dd2336 Mon Sep 17 00:00:00 2001 From: Shane Date: Fri, 11 Oct 2024 16:18:32 -0400 Subject: [PATCH 009/146] Added exports for multichain package (#4789) ## Explanation Added ESM exports for multichain package ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- packages/multichain/package.json | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index e633a1bb2b7..a1ad56d2925 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -27,6 +27,96 @@ "default": "./dist/index.cjs" } }, + "./caip25Permission": { + "import": { + "types": "./dist/caip25Permission.d.mts", + "default": "./dist/caip25Permission.mjs" + } + }, + "./adapters/caip-permission-adapter-eth-accounts": { + "import": { + "types": "./dist/adapters/caip-permission-adapter-eth-accounts.d.mts", + "default": "./dist/adapters/caip-permission-adapter-eth-accounts.mjs" + } + }, + "./adapters/caip-permission-adapter-middleware": { + "import": { + "types": "./dist/adapters/caip-permission-adapter-middleware.d.mts", + "default": "./dist/adapters/caip-permission-adapter-middleware.mjs" + } + }, + "./handlers/wallet-getSession": { + "import": { + "types": "./dist/handlers/wallet-getSession.d.mts", + "default": "./dist/handlers/wallet-getSession.mjs" + } + }, + "./handlers/wallet-invokeMethod": { + "import": { + "types": "./dist/handlers/wallet-invokeMethod.d.mts", + "default": "./dist/handlers/wallet-invokeMethod.mjs" + } + }, + "./handlers/wallet-revokeSession": { + "import": { + "types": "./dist/handlers/wallet-revokeSession.d.mts", + "default": "./dist/handlers/wallet-revokeSession.mjs" + } + }, + "./middlewares/MultichainMethodCallValidator": { + "import": { + "types": "./dist/middlewares/MultichainMethodCallValidator.d.mts", + "default": "./dist/middlewares/MultichainMethodCallValidator.mjs" + } + }, + "./middlewares/MultichainMiddlewareManager": { + "import": { + "types": "./dist/middlewares/MultichainMiddlewareManager.d.mts", + "default": "./dist/middlewares/MultichainMiddlewareManager.mjs" + } + }, + "./middlewares/MultichainSubscriptionManager": { + "import": { + "types": "./dist/middlewares/MultichainSubscriptionManager.d.mts", + "default": "./dist/middlewares/MultichainSubscriptionManager.mjs" + } + }, + "./scope/authorization": { + "import": { + "types": "./dist/scope/authorization.d.mts", + "default": "./dist/scope/authorization.mjs" + } + }, + "./scope/filter": { + "import": { + "types": "./dist/scope/filter.d.mts", + "default": "./dist/scope/filter.mjs" + } + }, + "./scope/scope": { + "import": { + "types": "./dist/scope/scope.d.mts", + "default": "./dist/scope/scope.mjs" + } + }, + "./scope/supported": { + "import": { + "types": "./dist/scope/supported.d.mts", + "default": "./dist/scope/supported.mjs" + } + }, + "./scope/transform": { + "import": { + "types": "./dist/scope/transform.d.mts", + "default": "./dist/scope/transform.mjs" + } + }, + "./scope/validation": { + "import": { + "types": "./dist/scope/validation.d.mts", + "default": "./dist/scope/validation.mjs" + } + }, "./package.json": "./package.json" }, "main": "./dist/index.cjs", From a0bb278a2a6c68f7d2f787d2598318d1b225f065 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 11 Oct 2024 13:43:24 -0700 Subject: [PATCH 010/146] Add requires --- packages/multichain/package.json | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index a1ad56d2925..56d08e29924 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -31,90 +31,150 @@ "import": { "types": "./dist/caip25Permission.d.mts", "default": "./dist/caip25Permission.mjs" + }, + "require": { + "types": "./dist/caip25Permission.d.cts", + "default": "./dist/caip25Permission.cjs" } }, "./adapters/caip-permission-adapter-eth-accounts": { "import": { "types": "./dist/adapters/caip-permission-adapter-eth-accounts.d.mts", "default": "./dist/adapters/caip-permission-adapter-eth-accounts.mjs" + }, + "require": { + "types": "./dist/adapters/caip-permission-adapter-eth-accounts.d.cts", + "default": "./dist/adapters/caip-permission-adapter-eth-accounts.cjs" } }, "./adapters/caip-permission-adapter-middleware": { "import": { "types": "./dist/adapters/caip-permission-adapter-middleware.d.mts", "default": "./dist/adapters/caip-permission-adapter-middleware.mjs" + }, + "require": { + "types": "./dist/adapters/caip-permission-adapter-middleware.d.cts", + "default": "./dist/adapters/caip-permission-adapter-middleware.cjs" } }, "./handlers/wallet-getSession": { "import": { "types": "./dist/handlers/wallet-getSession.d.mts", "default": "./dist/handlers/wallet-getSession.mjs" + }, + "require": { + "types": "./dist/handlers/wallet-getSession.d.cts", + "default": "./dist/handlers/wallet-getSession.cjs" } }, "./handlers/wallet-invokeMethod": { "import": { "types": "./dist/handlers/wallet-invokeMethod.d.mts", "default": "./dist/handlers/wallet-invokeMethod.mjs" + }, + "require": { + "types": "./dist/handlers/wallet-invokeMethod.d.cts", + "default": "./dist/handlers/wallet-invokeMethod.cjs" } }, "./handlers/wallet-revokeSession": { "import": { "types": "./dist/handlers/wallet-revokeSession.d.mts", "default": "./dist/handlers/wallet-revokeSession.mjs" + }, + "require": { + "types": "./dist/handlers/wallet-revokeSession.d.cts", + "default": "./dist/handlers/wallet-revokeSession.cjs" } }, "./middlewares/MultichainMethodCallValidator": { "import": { "types": "./dist/middlewares/MultichainMethodCallValidator.d.mts", "default": "./dist/middlewares/MultichainMethodCallValidator.mjs" + }, + "require": { + "types": "./dist/middlewares/MultichainMethodCallValidator.d.cts", + "default": "./dist/middlewares/MultichainMethodCallValidator.cjs" } }, "./middlewares/MultichainMiddlewareManager": { "import": { "types": "./dist/middlewares/MultichainMiddlewareManager.d.mts", "default": "./dist/middlewares/MultichainMiddlewareManager.mjs" + }, + "require": { + "types": "./dist/middlewares/MultichainMiddlewareManager.d.cts", + "default": "./dist/middlewares/MultichainMiddlewareManager.cjs" } }, "./middlewares/MultichainSubscriptionManager": { "import": { "types": "./dist/middlewares/MultichainSubscriptionManager.d.mts", "default": "./dist/middlewares/MultichainSubscriptionManager.mjs" + }, + "require": { + "types": "./dist/middlewares/MultichainSubscriptionManager.d.cts", + "default": "./dist/middlewares/MultichainSubscriptionManager.cjs" } }, "./scope/authorization": { "import": { "types": "./dist/scope/authorization.d.mts", "default": "./dist/scope/authorization.mjs" + }, + "require": { + "types": "./dist/scope/authorization.d.cts", + "default": "./dist/scope/authorization.cjs" } }, "./scope/filter": { "import": { "types": "./dist/scope/filter.d.mts", "default": "./dist/scope/filter.mjs" + }, + "require": { + "types": "./dist/scope/filter.d.cts", + "default": "./dist/scope/filter.cjs" } }, "./scope/scope": { "import": { "types": "./dist/scope/scope.d.mts", "default": "./dist/scope/scope.mjs" + }, + "require": { + "types": "./dist/scope/scope.d.cts", + "default": "./dist/scope/scope.cjs" } }, "./scope/supported": { "import": { "types": "./dist/scope/supported.d.mts", "default": "./dist/scope/supported.mjs" + }, + "require": { + "types": "./dist/scope/supported.d.cts", + "default": "./dist/scope/supported.cjs" } }, "./scope/transform": { "import": { "types": "./dist/scope/transform.d.mts", "default": "./dist/scope/transform.mjs" + }, + "require": { + "types": "./dist/scope/transform.d.cts", + "default": "./dist/scope/transform.cjs" } }, "./scope/validation": { "import": { "types": "./dist/scope/validation.d.mts", "default": "./dist/scope/validation.mjs" + }, + "require": { + "types": "./dist/scope/validation.d.cts", + "default": "./dist/scope/validation.cjs" } }, "./package.json": "./package.json" From 1cd8ef288acfce170984e0d1ff5e4783dec6f8d5 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 11 Oct 2024 14:11:37 -0700 Subject: [PATCH 011/146] add permittedChains adapter to exports --- packages/multichain/package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 56d08e29924..547a73d957a 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -57,6 +57,16 @@ "default": "./dist/adapters/caip-permission-adapter-middleware.cjs" } }, + "./adapters/caip-permission-adapter-permittedChains": { + "import": { + "types": "./dist/adapters/caip-permission-adapter-permittedChains.d.mts", + "default": "./dist/adapters/caip-permission-adapter-permittedChains.mjs" + }, + "require": { + "types": "./dist/adapters/caip-permission-adapter-permittedChains.d.cts", + "default": "./dist/adapters/caip-permission-adapter-permittedChains.cjs" + } + }, "./handlers/wallet-getSession": { "import": { "types": "./dist/handlers/wallet-getSession.d.mts", From c636def90f3c48c780337b6d5fa2a0ad4c240e25 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 11 Oct 2024 14:56:35 -0700 Subject: [PATCH 012/146] kill scope index barrel --- packages/multichain/jest.config.js | 4 +-- .../caip-permission-adapter-eth-accounts.ts | 5 +-- .../caip-permission-adapter-middleware.ts | 4 +-- ...permission-adapter-permittedChains.test.ts | 2 +- ...caip-permission-adapter-permittedChains.ts | 6 ++-- .../multichain/src/caip25Permission.test.ts | 35 +++++++++++-------- packages/multichain/src/caip25Permission.ts | 9 +++-- .../src/handlers/wallet-getSession.ts | 4 +-- .../src/handlers/wallet-invokeMethod.ts | 5 +-- .../MultichainMiddlewareManager.ts | 2 +- .../MultichainSubscriptionManager.ts | 2 +- packages/multichain/src/scope/index.ts | 7 ---- 12 files changed, 46 insertions(+), 39 deletions(-) delete mode 100644 packages/multichain/src/scope/index.ts diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js index f8be8cb30ee..2f651a645ea 100644 --- a/packages/multichain/jest.config.js +++ b/packages/multichain/jest.config.js @@ -19,8 +19,8 @@ module.exports = merge(baseConfig, { global: { branches: 83.05, functions: 87.37, - lines: 86.73, - statements: 87.17, + lines: 86.65, + statements: 87.09, }, }, }); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 95cb5dd0ec7..d47957cbc80 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -6,8 +6,9 @@ import { } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import type { ScopesObject } from '../scope'; -import { mergeScopes, parseScopeString, type ScopeString } from '../scope'; +import type { ScopesObject, ScopeString } from '../scope/scope'; +import { parseScopeString } from '../scope/scope'; +import { mergeScopes } from '../scope/transform'; const isEip155ScopeString = (scopeString: ScopeString) => { const { namespace, reference } = parseScopeString(scopeString); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index d92e0292e22..594d0bf7ae7 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -8,8 +8,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopeString } from '../scope'; -import { mergeScopes } from '../scope'; +import type { ScopeString } from '../scope/scope'; +import { mergeScopes } from '../scope/transform'; /** * Middleware to handle CAIP-25 permission requests. diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index a7402078079..665fc4779c6 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -1,5 +1,5 @@ import type { Caip25CaveatValue } from '../caip25Permission'; -import { KnownNotifications, KnownRpcMethods } from '../scope'; +import { KnownNotifications, KnownRpcMethods } from '../scope/scope'; import { addPermittedEthChainId, getPermittedEthChainIds, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index cfbbdedd298..6ec08ecd5c1 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,13 +3,13 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import type { ScopesObject, ScopeString } from '../scope'; +import type { ScopesObject, ScopeString } from '../scope/scope'; import { KnownNotifications, KnownRpcMethods, - mergeScopes, parseScopeString, -} from '../scope'; +} from '../scope/scope'; +import { mergeScopes } from '../scope/transform'; export const getPermittedEthChainIds = ( caip25CaveatValue: Caip25CaveatValue, diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index 7e6d6f243d7..eba34e350c3 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -14,19 +14,24 @@ import { Caip25CaveatMutatorFactories, removeScope, } from './caip25Permission'; -import * as Scope from './scope'; +import * as ScopeAssert from './scope/assert'; +import * as ScopeAuthorization from './scope/authorization'; -jest.mock('./scope', () => ({ +jest.mock('./scope/authorization', () => ({ validateAndFlattenScopes: jest.fn(), +})); +const MockScopeAuthorization = jest.mocked(ScopeAuthorization); + +jest.mock('./scope/assert', () => ({ assertScopesSupported: jest.fn(), })); -const MockScope = jest.mocked(Scope); +const MockScopeAssert = jest.mocked(ScopeAssert); const { removeAccount } = Caip25CaveatMutatorFactories[Caip25CaveatType]; describe('endowment:caip25', () => { beforeEach(() => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: {}, flattenedOptionalScopes: {}, }); @@ -409,7 +414,9 @@ describe('endowment:caip25', () => { } catch (err) { // noop } - expect(MockScope.validateAndFlattenScopes).toHaveBeenCalledWith( + expect( + MockScopeAuthorization.validateAndFlattenScopes, + ).toHaveBeenCalledWith( { 'eip155:1': { methods: ['eth_chainId'], @@ -428,7 +435,7 @@ describe('endowment:caip25', () => { }); it('asserts the validated and flattened required scopes are supported', () => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: { 'eip155:1': { methods: ['flattened_required'], @@ -474,7 +481,7 @@ describe('endowment:caip25', () => { } catch (err) { // noop } - expect(MockScope.assertScopesSupported).toHaveBeenCalledWith( + expect(MockScopeAssert.assertScopesSupported).toHaveBeenCalledWith( { 'eip155:1': { methods: ['flattened_required'], @@ -486,12 +493,12 @@ describe('endowment:caip25', () => { }), ); const isChainIdSupportedBody = - MockScope.assertScopesSupported.mock.calls[0][1].isChainIdSupported.toString(); + MockScopeAssert.assertScopesSupported.mock.calls[0][1].isChainIdSupported.toString(); expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); it('asserts the validated and flattened optional scopes are supported', () => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: { 'eip155:1': { methods: ['flattened_required'], @@ -537,7 +544,7 @@ describe('endowment:caip25', () => { } catch (err) { // noop } - expect(MockScope.assertScopesSupported).toHaveBeenCalledWith( + expect(MockScopeAssert.assertScopesSupported).toHaveBeenCalledWith( { 'eip155:1': { methods: ['flattened_optional'], @@ -549,12 +556,12 @@ describe('endowment:caip25', () => { }), ); const isChainIdSupportedBody = - MockScope.assertScopesSupported.mock.calls[1][1].isChainIdSupported.toString(); + MockScopeAssert.assertScopesSupported.mock.calls[1][1].isChainIdSupported.toString(); expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); it('throws if the input requiredScopes does not match the output of validateAndFlattenScopes', () => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: {}, flattenedOptionalScopes: { 'eip155:5': { @@ -597,7 +604,7 @@ describe('endowment:caip25', () => { }); it('throws if the input optionalScopes does not match the output of validateAndFlattenScopes', () => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: { 'eip155:1': { methods: ['eth_chainId'], @@ -640,7 +647,7 @@ describe('endowment:caip25', () => { }); it('does not throw if the input requiredScopes and optionalScopes ScopesObject are already validated and flattened', () => { - MockScope.validateAndFlattenScopes.mockReturnValue({ + MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ flattenedRequiredScopes: { 'eip155:1': { methods: ['eth_chainId'], diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index d4cb66428cd..2dd7b977394 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -20,8 +20,13 @@ import { import { strict as assert } from 'assert'; import { cloneDeep, isEqual } from 'lodash'; -import type { ExternalScopeString, ScopesObject, ScopeObject } from './scope'; -import { validateAndFlattenScopes, assertScopesSupported } from './scope'; +import { assertScopesSupported } from './scope/assert'; +import { validateAndFlattenScopes } from './scope/authorization'; +import type { + ExternalScopeString, + ScopeObject, + ScopesObject, +} from './scope/scope'; export type Caip25CaveatValue = { requiredScopes: ScopesObject; diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 7f0032d00d7..be5295b4ff6 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -6,8 +6,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopesObject } from '../scope'; -import { mergeScopes } from '../scope'; +import type { ScopesObject } from '../scope/scope'; +import { mergeScopes } from '../scope/transform'; /** * Handler for the `wallet_getSession` RPC method. diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 55f60060831..eea6d6a2b10 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -12,8 +12,9 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopeString } from '../scope'; -import { mergeScopes, parseScopeString } from '../scope'; +import type { ScopeString } from '../scope/scope'; +import { parseScopeString } from '../scope/scope'; +import { mergeScopes } from '../scope/transform'; /** * Handler for the `wallet_invokeMethod` RPC method. diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 205c6a67518..336b33978a1 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -8,7 +8,7 @@ import type { PendingJsonRpcResponse, } from '@metamask/utils'; -import type { ExternalScopeString } from '../scope'; +import type { ExternalScopeString } from '../scope/scope'; export type ExtendedJsonRpcMiddleware = { ( diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 7ffb75b7230..66f3ae550ab 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -5,7 +5,7 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { parseCaipChainId } from '@metamask/utils'; import type EventEmitter from 'events'; -import type { ExternalScopeString } from '../scope'; +import type { ExternalScopeString } from '../scope/scope'; export type SubscriptionManager = { events: EventEmitter; diff --git a/packages/multichain/src/scope/index.ts b/packages/multichain/src/scope/index.ts deleted file mode 100644 index c1b804efecb..00000000000 --- a/packages/multichain/src/scope/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './assert'; -export * from './authorization'; -export * from './filter'; -export * from './scope'; -export * from './supported'; -export * from './transform'; -export * from './validation'; From a6aa7c1a5f6ad9074f155d71665af74781963f20 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 08:30:45 -0700 Subject: [PATCH 013/146] barrel --- packages/multichain/package.json | 160 ------------------ .../caip-permission-adapter-eth-accounts.ts | 4 +- .../caip-permission-adapter-middleware.ts | 2 +- ...permission-adapter-permittedChains.test.ts | 2 +- ...caip-permission-adapter-permittedChains.ts | 4 +- packages/multichain/src/caip25Permission.ts | 2 +- .../src/handlers/wallet-getSession.ts | 2 +- .../src/handlers/wallet-invokeMethod.ts | 4 +- packages/multichain/src/index.test.ts | 52 +++++- packages/multichain/src/index.ts | 30 +++- .../MultichainMiddlewareManager.test.ts | 2 +- .../MultichainMiddlewareManager.ts | 4 +- .../MultichainSubscriptionManager.test.ts | 2 +- .../MultichainSubscriptionManager.ts | 4 +- .../multichainMethodCallValidator.ts | 2 +- packages/multichain/src/scope/assert.test.ts | 2 +- packages/multichain/src/scope/assert.ts | 2 +- .../src/scope/authorization.test.ts | 2 +- .../multichain/src/scope/authorization.ts | 2 +- packages/multichain/src/scope/filter.ts | 2 +- packages/multichain/src/scope/scope.test.ts | 2 +- .../multichain/src/scope/supported.test.ts | 2 +- packages/multichain/src/scope/supported.ts | 4 +- .../multichain/src/scope/transform.test.ts | 2 +- packages/multichain/src/scope/transform.ts | 4 +- .../src/scope/{scope.ts => types.ts} | 0 .../multichain/src/scope/validation.test.ts | 2 +- packages/multichain/src/scope/validation.ts | 4 +- 28 files changed, 99 insertions(+), 207 deletions(-) rename packages/multichain/src/scope/{scope.ts => types.ts} (100%) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 547a73d957a..e633a1bb2b7 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -27,166 +27,6 @@ "default": "./dist/index.cjs" } }, - "./caip25Permission": { - "import": { - "types": "./dist/caip25Permission.d.mts", - "default": "./dist/caip25Permission.mjs" - }, - "require": { - "types": "./dist/caip25Permission.d.cts", - "default": "./dist/caip25Permission.cjs" - } - }, - "./adapters/caip-permission-adapter-eth-accounts": { - "import": { - "types": "./dist/adapters/caip-permission-adapter-eth-accounts.d.mts", - "default": "./dist/adapters/caip-permission-adapter-eth-accounts.mjs" - }, - "require": { - "types": "./dist/adapters/caip-permission-adapter-eth-accounts.d.cts", - "default": "./dist/adapters/caip-permission-adapter-eth-accounts.cjs" - } - }, - "./adapters/caip-permission-adapter-middleware": { - "import": { - "types": "./dist/adapters/caip-permission-adapter-middleware.d.mts", - "default": "./dist/adapters/caip-permission-adapter-middleware.mjs" - }, - "require": { - "types": "./dist/adapters/caip-permission-adapter-middleware.d.cts", - "default": "./dist/adapters/caip-permission-adapter-middleware.cjs" - } - }, - "./adapters/caip-permission-adapter-permittedChains": { - "import": { - "types": "./dist/adapters/caip-permission-adapter-permittedChains.d.mts", - "default": "./dist/adapters/caip-permission-adapter-permittedChains.mjs" - }, - "require": { - "types": "./dist/adapters/caip-permission-adapter-permittedChains.d.cts", - "default": "./dist/adapters/caip-permission-adapter-permittedChains.cjs" - } - }, - "./handlers/wallet-getSession": { - "import": { - "types": "./dist/handlers/wallet-getSession.d.mts", - "default": "./dist/handlers/wallet-getSession.mjs" - }, - "require": { - "types": "./dist/handlers/wallet-getSession.d.cts", - "default": "./dist/handlers/wallet-getSession.cjs" - } - }, - "./handlers/wallet-invokeMethod": { - "import": { - "types": "./dist/handlers/wallet-invokeMethod.d.mts", - "default": "./dist/handlers/wallet-invokeMethod.mjs" - }, - "require": { - "types": "./dist/handlers/wallet-invokeMethod.d.cts", - "default": "./dist/handlers/wallet-invokeMethod.cjs" - } - }, - "./handlers/wallet-revokeSession": { - "import": { - "types": "./dist/handlers/wallet-revokeSession.d.mts", - "default": "./dist/handlers/wallet-revokeSession.mjs" - }, - "require": { - "types": "./dist/handlers/wallet-revokeSession.d.cts", - "default": "./dist/handlers/wallet-revokeSession.cjs" - } - }, - "./middlewares/MultichainMethodCallValidator": { - "import": { - "types": "./dist/middlewares/MultichainMethodCallValidator.d.mts", - "default": "./dist/middlewares/MultichainMethodCallValidator.mjs" - }, - "require": { - "types": "./dist/middlewares/MultichainMethodCallValidator.d.cts", - "default": "./dist/middlewares/MultichainMethodCallValidator.cjs" - } - }, - "./middlewares/MultichainMiddlewareManager": { - "import": { - "types": "./dist/middlewares/MultichainMiddlewareManager.d.mts", - "default": "./dist/middlewares/MultichainMiddlewareManager.mjs" - }, - "require": { - "types": "./dist/middlewares/MultichainMiddlewareManager.d.cts", - "default": "./dist/middlewares/MultichainMiddlewareManager.cjs" - } - }, - "./middlewares/MultichainSubscriptionManager": { - "import": { - "types": "./dist/middlewares/MultichainSubscriptionManager.d.mts", - "default": "./dist/middlewares/MultichainSubscriptionManager.mjs" - }, - "require": { - "types": "./dist/middlewares/MultichainSubscriptionManager.d.cts", - "default": "./dist/middlewares/MultichainSubscriptionManager.cjs" - } - }, - "./scope/authorization": { - "import": { - "types": "./dist/scope/authorization.d.mts", - "default": "./dist/scope/authorization.mjs" - }, - "require": { - "types": "./dist/scope/authorization.d.cts", - "default": "./dist/scope/authorization.cjs" - } - }, - "./scope/filter": { - "import": { - "types": "./dist/scope/filter.d.mts", - "default": "./dist/scope/filter.mjs" - }, - "require": { - "types": "./dist/scope/filter.d.cts", - "default": "./dist/scope/filter.cjs" - } - }, - "./scope/scope": { - "import": { - "types": "./dist/scope/scope.d.mts", - "default": "./dist/scope/scope.mjs" - }, - "require": { - "types": "./dist/scope/scope.d.cts", - "default": "./dist/scope/scope.cjs" - } - }, - "./scope/supported": { - "import": { - "types": "./dist/scope/supported.d.mts", - "default": "./dist/scope/supported.mjs" - }, - "require": { - "types": "./dist/scope/supported.d.cts", - "default": "./dist/scope/supported.cjs" - } - }, - "./scope/transform": { - "import": { - "types": "./dist/scope/transform.d.mts", - "default": "./dist/scope/transform.mjs" - }, - "require": { - "types": "./dist/scope/transform.d.cts", - "default": "./dist/scope/transform.cjs" - } - }, - "./scope/validation": { - "import": { - "types": "./dist/scope/validation.d.mts", - "default": "./dist/scope/validation.mjs" - }, - "require": { - "types": "./dist/scope/validation.d.cts", - "default": "./dist/scope/validation.cjs" - } - }, "./package.json": "./package.json" }, "main": "./dist/index.cjs", diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index d47957cbc80..db459460cca 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -6,8 +6,8 @@ import { } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import type { ScopesObject, ScopeString } from '../scope/scope'; -import { parseScopeString } from '../scope/scope'; +import type { ScopesObject, ScopeString } from '../scope/types'; +import { parseScopeString } from '../scope/types'; import { mergeScopes } from '../scope/transform'; const isEip155ScopeString = (scopeString: ScopeString) => { diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 594d0bf7ae7..1ce16cee3b8 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -8,7 +8,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopeString } from '../scope/scope'; +import type { ScopeString } from '../scope/types'; import { mergeScopes } from '../scope/transform'; /** diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 665fc4779c6..127a15cb40b 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -1,5 +1,5 @@ import type { Caip25CaveatValue } from '../caip25Permission'; -import { KnownNotifications, KnownRpcMethods } from '../scope/scope'; +import { KnownNotifications, KnownRpcMethods } from '../scope/types'; import { addPermittedEthChainId, getPermittedEthChainIds, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 6ec08ecd5c1..5913a1f61c3 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,12 +3,12 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import type { ScopesObject, ScopeString } from '../scope/scope'; +import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownNotifications, KnownRpcMethods, parseScopeString, -} from '../scope/scope'; +} from '../scope/types'; import { mergeScopes } from '../scope/transform'; export const getPermittedEthChainIds = ( diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index 2dd7b977394..b3ad6e8a8b6 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -26,7 +26,7 @@ import type { ExternalScopeString, ScopeObject, ScopesObject, -} from './scope/scope'; +} from './scope/types'; export type Caip25CaveatValue = { requiredScopes: ScopesObject; diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index be5295b4ff6..8df6526260e 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -6,7 +6,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopesObject } from '../scope/scope'; +import type { ScopesObject } from '../scope/types'; import { mergeScopes } from '../scope/transform'; /** diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index eea6d6a2b10..8faaef066c4 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -12,8 +12,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopeString } from '../scope/scope'; -import { parseScopeString } from '../scope/scope'; +import type { ScopeString } from '../scope/types'; +import { parseScopeString } from '../scope/types'; import { mergeScopes } from '../scope/transform'; /** diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index bc062d3694a..ffb2b2b8b76 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -1,9 +1,49 @@ -import greeter from '.'; +import * as allExports from '.'; -describe('Test', () => { - it('greets', () => { - const name = 'Huey'; - const result = greeter(name); - expect(result).toBe('Hello, Huey!'); +describe('@metamask/multichain', () => { + it('has expected JavaScript exports', () => { + expect(Object.keys(allExports)).toMatchInlineSnapshot(` + Array [ + "getEthAccounts", + "setEthAccounts", + "caipPermissionAdapterMiddleware", + "getPermittedEthChainIds", + "addPermittedEthChainId", + "setPermittedEthChainIds", + "walletGetSessionHandler", + "walletInvokeMethodHandler", + "walletRevokeSessionHandler", + "multichainMethodCallValidatorMiddleware", + "MultichainMiddlewareManager", + "MultichainSubscriptionManager", + "Caip25CaveatType", + "Caip25CaveatFactoryFn", + "Caip25EndowmentPermissionName", + "caip25EndowmentBuilder", + "Caip25CaveatMutatorFactories", + "removeScope", + "assertScopeSupported", + "assertScopesSupported", + "validateAndFlattenScopes", + "bucketScopes", + "bucketScopesBySupport", + "filterScopesSupported", + "isSupportedScopeString", + "isSupportedAccount", + "isSupportedMethod", + "isSupportedNotification", + "flattenScope", + "mergeScopeObject", + "mergeScopes", + "flattenMergeScopes", + "isValidScope", + "validateScopes", + "KnownWalletRpcMethods", + "KnownRpcMethods", + "KnownWalletNamespaceRpcMethods", + "KnownNotifications", + "parseScopeString", + ] + `); }); }); diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 6972c117292..e9caf04f5a1 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -1,9 +1,21 @@ -/** - * Example function that returns a greeting for the given name. - * - * @param name - The name to greet. - * @returns The greeting. - */ -export default function greeter(name: string): string { - return `Hello, ${name}!`; -} +export { getEthAccounts, setEthAccounts } from './adapters/caip-permission-adapter-eth-accounts' +export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware' +export { getPermittedEthChainIds, addPermittedEthChainId, setPermittedEthChainIds} from './adapters/caip-permission-adapter-permittedChains' + +export { walletGetSessionHandler } from './handlers/wallet-getSession' +export { walletInvokeMethodHandler } from './handlers/wallet-invokeMethod' +export { walletRevokeSessionHandler } from './handlers/wallet-revokeSession' + +export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator' +export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager' +export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager' + +export {assertScopeSupported, assertScopesSupported} from './scope/assert' +export { Caip25Authorization, validateAndFlattenScopes, bucketScopes } from './scope/authorization' +export {bucketScopesBySupport, filterScopesSupported} from './scope/filter' +export * from './scope/types' +export {isSupportedScopeString, isSupportedAccount, isSupportedMethod, isSupportedNotification} from './scope/supported' +export {flattenScope, mergeScopeObject, mergeScopes, flattenMergeScopes } from './scope/transform' +export {isValidScope, validateScopes} from './scope/validation' + +export { Caip25CaveatValue, Caip25CaveatType, Caip25CaveatFactoryFn, Caip25EndowmentPermissionName, caip25EndowmentBuilder, Caip25CaveatMutatorFactories, removeScope } from './caip25Permission' diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index c6097529946..4a358896fce 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -1,5 +1,5 @@ import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; -import MultichainMiddlewareManager from './MultichainMiddlewareManager'; +import { MultichainMiddlewareManager } from './MultichainMiddlewareManager'; const scope = 'eip155:1'; const origin = 'example.com'; diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 336b33978a1..d1e52f93852 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -8,7 +8,7 @@ import type { PendingJsonRpcResponse, } from '@metamask/utils'; -import type { ExternalScopeString } from '../scope/scope'; +import type { ExternalScopeString } from '../scope/types'; export type ExtendedJsonRpcMiddleware = { ( @@ -29,7 +29,7 @@ type MiddlewareEntry = MiddlewareKey & { middleware: ExtendedJsonRpcMiddleware; }; -export default class MultichainMiddlewareManager { +export class MultichainMiddlewareManager { #middlewares: MiddlewareEntry[] = []; #getMiddlewareEntry({ diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index c951b711af7..cf05aa5c5a9 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -1,6 +1,6 @@ import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; -import MultichainSubscriptionManager from './MultichainSubscriptionManager'; +import { MultichainSubscriptionManager } from './MultichainSubscriptionManager'; jest.mock('@metamask/eth-json-rpc-filters/subscriptionManager', () => jest.fn(), diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 66f3ae550ab..0fed86cfd92 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -5,7 +5,7 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { parseCaipChainId } from '@metamask/utils'; import type EventEmitter from 'events'; -import type { ExternalScopeString } from '../scope/scope'; +import type { ExternalScopeString } from '../scope/types'; export type SubscriptionManager = { events: EventEmitter; @@ -38,7 +38,7 @@ type MultichainSubscriptionManagerOptions = { getNetworkClientById: NetworkController['getNetworkClientById']; }; -export default class MultichainSubscriptionManager extends SafeEventEmitter { +export class MultichainSubscriptionManager extends SafeEventEmitter { #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; #getNetworkClientById: NetworkController['getNetworkClientById']; diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index a57ac7835a6..d62b2328eba 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -46,7 +46,7 @@ const dereffedPromise = dereferenceDocument( MultiChainOpenRPCDocument as unknown as OpenrpcDocument, makeCustomResolver({}), ); -export const multichainMethodCallValidator = async ( +const multichainMethodCallValidator = async ( method: string, params: JsonRpcParams | undefined, ) => { diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 75485352bac..2f8d9341275 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -1,7 +1,7 @@ import { JsonRpcError } from '@metamask/rpc-errors'; import { assertScopeSupported, assertScopesSupported } from './assert'; -import type { ScopeObject } from './scope'; +import type { ScopeObject } from './types'; import * as Supported from './supported'; jest.mock('./supported', () => ({ diff --git a/packages/multichain/src/scope/assert.ts b/packages/multichain/src/scope/assert.ts index ea436fb9091..9d7b090665a 100644 --- a/packages/multichain/src/scope/assert.ts +++ b/packages/multichain/src/scope/assert.ts @@ -1,7 +1,7 @@ import { JsonRpcError } from '@metamask/rpc-errors'; import type { Hex } from '@metamask/utils'; -import type { ScopeObject, ScopesObject } from './scope'; +import type { ScopeObject, ScopesObject } from './types'; import { isSupportedMethod, isSupportedNotification, diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 318718133d3..6b5b9cfc146 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,6 +1,6 @@ import { bucketScopes, validateAndFlattenScopes } from './authorization'; import * as Filter from './filter'; -import type { ExternalScopeObject } from './scope'; +import type { ExternalScopeObject } from './types'; import * as Transform from './transform'; import * as Validation from './validation'; diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index 3b4f5e06199..b44e7f55447 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,7 +1,7 @@ import type { Hex } from '@metamask/utils'; import { bucketScopesBySupport } from './filter'; -import type { ExternalScopesObject, ScopesObject } from './scope'; +import type { ExternalScopesObject, ScopesObject } from './types'; import { flattenMergeScopes } from './transform'; import { validateScopes } from './validation'; diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index ab5e889af17..58157bd6027 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -1,7 +1,7 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { assertScopeSupported } from './assert'; -import type { ScopesObject } from './scope'; +import type { ScopesObject } from './types'; export const bucketScopesBySupport = ( scopes: ScopesObject, diff --git a/packages/multichain/src/scope/scope.test.ts b/packages/multichain/src/scope/scope.test.ts index d3a58b3221a..1b6149b3f2e 100644 --- a/packages/multichain/src/scope/scope.test.ts +++ b/packages/multichain/src/scope/scope.test.ts @@ -1,4 +1,4 @@ -import { parseScopeString } from './scope'; +import { parseScopeString } from './types'; describe('Scope', () => { describe('parseScopeString', () => { diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts index b8146ebd157..bba7e40f207 100644 --- a/packages/multichain/src/scope/supported.test.ts +++ b/packages/multichain/src/scope/supported.test.ts @@ -3,7 +3,7 @@ import { KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, -} from './scope'; +} from './types'; import { isSupportedMethod, isSupportedNotification, diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts index 80ceb961f4d..364e2cd249a 100644 --- a/packages/multichain/src/scope/supported.ts +++ b/packages/multichain/src/scope/supported.ts @@ -8,14 +8,14 @@ import { parseCaipChainId, } from '@metamask/utils'; -import type { NonWalletKnownCaipNamespace, ExternalScopeString } from './scope'; +import type { NonWalletKnownCaipNamespace, ExternalScopeString } from './types'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, parseScopeString, -} from './scope'; +} from './types'; // TODO Maybe this gets DRY'ed into utils?.. It's used in TokenDetectionController too /** diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index d092735eb67..e57e85f565a 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -1,4 +1,4 @@ -import type { ExternalScopeObject } from './scope'; +import type { ExternalScopeObject } from './types'; import { flattenScope, mergeScopes, diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts index 097ad725d89..a5bb2e9070f 100644 --- a/packages/multichain/src/scope/transform.ts +++ b/packages/multichain/src/scope/transform.ts @@ -7,8 +7,8 @@ import type { ScopeString, ScopeObject, ScopesObject, -} from './scope'; -import { parseScopeString } from './scope'; +} from './types'; +import { parseScopeString } from './types'; // TODO: DRY THIS /** diff --git a/packages/multichain/src/scope/scope.ts b/packages/multichain/src/scope/types.ts similarity index 100% rename from packages/multichain/src/scope/scope.ts rename to packages/multichain/src/scope/types.ts diff --git a/packages/multichain/src/scope/validation.test.ts b/packages/multichain/src/scope/validation.test.ts index f4f4ae63e34..e8cfb962804 100644 --- a/packages/multichain/src/scope/validation.test.ts +++ b/packages/multichain/src/scope/validation.test.ts @@ -1,4 +1,4 @@ -import type { ExternalScopeObject } from './scope'; +import type { ExternalScopeObject } from './types'; import { isValidScope, validateScopes } from './validation'; const validScopeString = 'eip155:1'; diff --git a/packages/multichain/src/scope/validation.ts b/packages/multichain/src/scope/validation.ts index 69bc3e1bb9c..3dbb7cfa252 100644 --- a/packages/multichain/src/scope/validation.ts +++ b/packages/multichain/src/scope/validation.ts @@ -4,8 +4,8 @@ import type { ExternalScopeString, ExternalScopeObject, ExternalScopesObject, -} from './scope'; -import { parseScopeString } from './scope'; +} from './types'; +import { parseScopeString } from './types'; export const isValidScope = ( scopeString: ExternalScopeString, From a13b9c75d85294f117965d7d36c1cc5cdf3181e8 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 09:38:42 -0700 Subject: [PATCH 014/146] remove subjectTypes from CAIP-25 permission --- packages/multichain/src/caip25Permission.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index b3ad6e8a8b6..cbf6bf39323 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -9,7 +9,6 @@ import type { import { CaveatMutatorOperation, PermissionType, - SubjectType, } from '@metamask/permission-controller'; import type { CaipAccountId, Json } from '@metamask/utils'; import { @@ -77,7 +76,6 @@ const specificationBuilder: PermissionSpecificationBuilder< targetName: Caip25EndowmentPermissionName, allowedCaveats: [Caip25CaveatType], endowmentGetter: (_getterOptions?: EndowmentGetterParams) => null, - subjectTypes: [SubjectType.Website], validator: (permission: PermissionConstraint) => { const caip25Caveat = permission.caveats?.[0]; if ( From 81db87755a680def5847ace9fd07cbc80dfb0528 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 09:52:51 -0700 Subject: [PATCH 015/146] update eth accounts adapter with empty wallet and wallet:eip155 ScopeObjects --- ...ip-permission-adapter-eth-accounts.test.ts | 34 +++++++++++++++++++ .../caip-permission-adapter-eth-accounts.ts | 12 ++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index 9434fab81d9..76fe6d28802 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -177,6 +177,40 @@ describe('CAIP-25 eth_accounts adapters', () => { }); }); + it('returns a CAIP-25 caveat value with "wallet" and "wallet:eip155" scopes with CAIP-10 account addresses formed from the accounts param when the "wallet" or "wallet:eip155" are not defined in optional scopes', () => { + const input: Caip25CaveatValue = { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: false, + }; + + const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); + expect(result).toStrictEqual({ + requiredScopes: {}, + optionalScopes: { + wallet: { + methods: [], + notifications: [], + accounts: [ + 'wallet:eip155:0x1', + 'wallet:eip155:0x2', + 'wallet:eip155:0x3', + ], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + accounts: [ + 'wallet:eip155:0x1', + 'wallet:eip155:0x2', + 'wallet:eip155:0x3', + ], + }, + }, + isMultichainOrigin: false, + }); + }); + it('does not modify the input CAIP-25 caveat value object in place', () => { const input: Caip25CaveatValue = { requiredScopes: { diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index db459460cca..569e3e9380d 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -88,7 +88,17 @@ export const setEthAccounts = ( accounts, ), optionalScopes: setEthAccountsForScopesObject( - caip25CaveatValue.optionalScopes, + { + wallet: { + methods: [], + notifications: [], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, + ...caip25CaveatValue.optionalScopes, + }, accounts, ), }; From a3fc2639dc767d8447195efa3d62f06dbfd397af Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 10:37:04 -0700 Subject: [PATCH 016/146] fix caip25permission spec --- packages/multichain/src/caip25Permission.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index eba34e350c3..af1b92745c6 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -3,7 +3,6 @@ import type { CaveatConstraint } from '@metamask/permission-controller'; import { CaveatMutatorOperation, PermissionType, - SubjectType, } from '@metamask/permission-controller'; import type { Caip25CaveatValue } from './caip25Permission'; @@ -52,7 +51,6 @@ describe('endowment:caip25', () => { targetName: Caip25EndowmentPermissionName, endowmentGetter: expect.any(Function), allowedCaveats: [Caip25CaveatType], - subjectTypes: [SubjectType.Website], validator: expect.any(Function), }); From afe5cb9307792f20a9a8668a91ffc43f6d7ada3a Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 10:37:21 -0700 Subject: [PATCH 017/146] upsert empty wallet:eip155 when setting permittedChains --- ...permission-adapter-permittedChains.test.ts | 62 +++++++++++++++++++ ...caip-permission-adapter-permittedChains.ts | 4 ++ 2 files changed, 66 insertions(+) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 127a15cb40b..2ca86004f3a 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -69,6 +69,10 @@ describe('CAIP-25 permittedChains adapters', () => { notifications: [], accounts: ['eip155:100:0x100'], }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, }, isMultichainOrigin: false, }, @@ -94,6 +98,60 @@ describe('CAIP-25 permittedChains adapters', () => { notifications: KnownNotifications.eip155, accounts: [], }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, + }, + isMultichainOrigin: false, + }); + }); + + it('adds an optional scope for "wallet:eip155" if it does not already exist in the optional scopes', () => { + const result = addPermittedEthChainId( + { + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + }, + isMultichainOrigin: false, + }, + '0x65', + ); + + expect(result).toStrictEqual({ + requiredScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + optionalScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:100:0x100'], + }, + 'eip155:101': { + methods: KnownRpcMethods.eip155, + notifications: KnownNotifications.eip155, + accounts: [], + }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, }, isMultichainOrigin: false, }); @@ -277,6 +335,10 @@ describe('CAIP-25 permittedChains adapters', () => { notifications: KnownNotifications.eip155, accounts: [], }, + 'wallet:eip155': { + methods: [], + notifications: [], + }, }, isMultichainOrigin: false, }); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 5913a1f61c3..7a0ad8196f3 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -45,6 +45,10 @@ export const addPermittedEthChainId = ( return { ...caip25CaveatValue, optionalScopes: { + 'wallet:eip155': { + methods: [], + notifications: [], + }, ...caip25CaveatValue.optionalScopes, [scopeString]: { methods: KnownRpcMethods.eip155, From 9ea78bee99e6d4eaf0a8778632599f0135559960 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 10:47:29 -0700 Subject: [PATCH 018/146] lint --- .../caip-permission-adapter-eth-accounts.ts | 2 +- .../caip-permission-adapter-middleware.ts | 2 +- ...caip-permission-adapter-permittedChains.ts | 2 +- .../src/handlers/wallet-getSession.ts | 2 +- .../src/handlers/wallet-invokeMethod.ts | 2 +- packages/multichain/src/index.ts | 60 +++++++++++++------ packages/multichain/src/scope/assert.test.ts | 2 +- packages/multichain/src/scope/assert.ts | 2 +- .../src/scope/authorization.test.ts | 2 +- .../multichain/src/scope/authorization.ts | 2 +- .../multichain/src/scope/supported.test.ts | 10 ++-- .../multichain/src/scope/transform.test.ts | 2 +- 12 files changed, 58 insertions(+), 32 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 569e3e9380d..5646bab107a 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -6,9 +6,9 @@ import { } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { parseScopeString } from '../scope/types'; -import { mergeScopes } from '../scope/transform'; const isEip155ScopeString = (scopeString: ScopeString) => { const { namespace, reference } = parseScopeString(scopeString); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 1ce16cee3b8..6c8378b40d8 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -8,8 +8,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopeString } from '../scope/types'; import { mergeScopes } from '../scope/transform'; +import type { ScopeString } from '../scope/types'; /** * Middleware to handle CAIP-25 permission requests. diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 7a0ad8196f3..c0042dbfe96 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,13 +3,13 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownNotifications, KnownRpcMethods, parseScopeString, } from '../scope/types'; -import { mergeScopes } from '../scope/transform'; export const getPermittedEthChainIds = ( caip25CaveatValue: Caip25CaveatValue, diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 8df6526260e..13c9e4f0170 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -6,8 +6,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import type { ScopesObject } from '../scope/types'; import { mergeScopes } from '../scope/transform'; +import type { ScopesObject } from '../scope/types'; /** * Handler for the `wallet_getSession` RPC method. diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 8faaef066c4..239d65195b4 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -12,9 +12,9 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; import type { ScopeString } from '../scope/types'; import { parseScopeString } from '../scope/types'; -import { mergeScopes } from '../scope/transform'; /** * Handler for the `wallet_invokeMethod` RPC method. diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index e9caf04f5a1..55a4cd38221 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -1,21 +1,47 @@ -export { getEthAccounts, setEthAccounts } from './adapters/caip-permission-adapter-eth-accounts' -export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware' -export { getPermittedEthChainIds, addPermittedEthChainId, setPermittedEthChainIds} from './adapters/caip-permission-adapter-permittedChains' +export { + getEthAccounts, + setEthAccounts, +} from './adapters/caip-permission-adapter-eth-accounts'; +export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; +export { + getPermittedEthChainIds, + addPermittedEthChainId, + setPermittedEthChainIds, +} from './adapters/caip-permission-adapter-permittedChains'; -export { walletGetSessionHandler } from './handlers/wallet-getSession' -export { walletInvokeMethodHandler } from './handlers/wallet-invokeMethod' -export { walletRevokeSessionHandler } from './handlers/wallet-revokeSession' +export { walletGetSessionHandler } from './handlers/wallet-getSession'; +export { walletInvokeMethodHandler } from './handlers/wallet-invokeMethod'; +export { walletRevokeSessionHandler } from './handlers/wallet-revokeSession'; -export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator' -export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager' -export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager' +export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator'; +export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager'; +export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager'; -export {assertScopeSupported, assertScopesSupported} from './scope/assert' -export { Caip25Authorization, validateAndFlattenScopes, bucketScopes } from './scope/authorization' -export {bucketScopesBySupport, filterScopesSupported} from './scope/filter' -export * from './scope/types' -export {isSupportedScopeString, isSupportedAccount, isSupportedMethod, isSupportedNotification} from './scope/supported' -export {flattenScope, mergeScopeObject, mergeScopes, flattenMergeScopes } from './scope/transform' -export {isValidScope, validateScopes} from './scope/validation' +export { assertScopeSupported, assertScopesSupported } from './scope/assert'; +export type { Caip25Authorization } from './scope/authorization'; +export { validateAndFlattenScopes, bucketScopes } from './scope/authorization'; +export { bucketScopesBySupport, filterScopesSupported } from './scope/filter'; +export * from './scope/types'; +export { + isSupportedScopeString, + isSupportedAccount, + isSupportedMethod, + isSupportedNotification, +} from './scope/supported'; +export { + flattenScope, + mergeScopeObject, + mergeScopes, + flattenMergeScopes, +} from './scope/transform'; +export { isValidScope, validateScopes } from './scope/validation'; -export { Caip25CaveatValue, Caip25CaveatType, Caip25CaveatFactoryFn, Caip25EndowmentPermissionName, caip25EndowmentBuilder, Caip25CaveatMutatorFactories, removeScope } from './caip25Permission' +export type { Caip25CaveatValue } from './caip25Permission'; +export { + Caip25CaveatType, + Caip25CaveatFactoryFn, + Caip25EndowmentPermissionName, + caip25EndowmentBuilder, + Caip25CaveatMutatorFactories, + removeScope, +} from './caip25Permission'; diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 2f8d9341275..92e936a741b 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -1,8 +1,8 @@ import { JsonRpcError } from '@metamask/rpc-errors'; import { assertScopeSupported, assertScopesSupported } from './assert'; -import type { ScopeObject } from './types'; import * as Supported from './supported'; +import type { ScopeObject } from './types'; jest.mock('./supported', () => ({ isSupportedScopeString: jest.fn(), diff --git a/packages/multichain/src/scope/assert.ts b/packages/multichain/src/scope/assert.ts index 9d7b090665a..77a9dd62050 100644 --- a/packages/multichain/src/scope/assert.ts +++ b/packages/multichain/src/scope/assert.ts @@ -1,12 +1,12 @@ import { JsonRpcError } from '@metamask/rpc-errors'; import type { Hex } from '@metamask/utils'; -import type { ScopeObject, ScopesObject } from './types'; import { isSupportedMethod, isSupportedNotification, isSupportedScopeString, } from './supported'; +import type { ScopeObject, ScopesObject } from './types'; export const assertScopeSupported = ( scopeString: string, diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 6b5b9cfc146..44e6323f388 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,7 +1,7 @@ import { bucketScopes, validateAndFlattenScopes } from './authorization'; import * as Filter from './filter'; -import type { ExternalScopeObject } from './types'; import * as Transform from './transform'; +import type { ExternalScopeObject } from './types'; import * as Validation from './validation'; jest.mock('./validation', () => ({ diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index b44e7f55447..9b377a8b137 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,8 +1,8 @@ import type { Hex } from '@metamask/utils'; import { bucketScopesBySupport } from './filter'; -import type { ExternalScopesObject, ScopesObject } from './types'; import { flattenMergeScopes } from './transform'; +import type { ExternalScopesObject, ScopesObject } from './types'; import { validateScopes } from './validation'; export type Caip25Authorization = diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts index bba7e40f207..72faf0e50d3 100644 --- a/packages/multichain/src/scope/supported.test.ts +++ b/packages/multichain/src/scope/supported.test.ts @@ -1,14 +1,14 @@ +import { + isSupportedMethod, + isSupportedNotification, + isSupportedScopeString, +} from './supported'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, } from './types'; -import { - isSupportedMethod, - isSupportedNotification, - isSupportedScopeString, -} from './supported'; describe('Scope Support', () => { describe('isSupportedNotification', () => { diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index e57e85f565a..acfc694e7db 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -1,10 +1,10 @@ -import type { ExternalScopeObject } from './types'; import { flattenScope, mergeScopes, mergeScopeObject, flattenMergeScopes, } from './transform'; +import type { ExternalScopeObject } from './types'; const validScopeObject: ExternalScopeObject = { methods: [], From 5650d31fca65e609d778e4ac5fa8eb97e1787913 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 14 Oct 2024 10:52:53 -0700 Subject: [PATCH 019/146] Rename scope.test.ts to types.test.ts --- packages/multichain/src/scope/{scope.test.ts => types.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/multichain/src/scope/{scope.test.ts => types.test.ts} (100%) diff --git a/packages/multichain/src/scope/scope.test.ts b/packages/multichain/src/scope/types.test.ts similarity index 100% rename from packages/multichain/src/scope/scope.test.ts rename to packages/multichain/src/scope/types.test.ts From df5167ebef9fffb60b8caf57544346554edc7ae5 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 08:17:01 -0700 Subject: [PATCH 020/146] add networkClientId type to permission-adapter-middleware --- .../src/adapters/caip-permission-adapter-middleware.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 6c8378b40d8..811978697f3 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -1,4 +1,7 @@ -import type { NetworkConfiguration } from '@metamask/network-controller'; +import type { + NetworkConfiguration, + NetworkClientId, +} from '@metamask/network-controller'; import type { Caveat } from '@metamask/permission-controller'; import { providerErrors } from '@metamask/rpc-errors'; import type { JsonRpcRequest } from '@metamask/utils'; @@ -24,7 +27,7 @@ import type { ScopeString } from '../scope/types'; */ export async function caipPermissionAdapterMiddleware( request: JsonRpcRequest & { - networkClientId: string; + networkClientId: NetworkClientId; origin: string; }, _response: unknown, @@ -35,7 +38,7 @@ export async function caipPermissionAdapterMiddleware( ...args: unknown[] ) => Caveat; getNetworkConfigurationByNetworkClientId: ( - networkClientId: string, + networkClientId: NetworkClientId, ) => NetworkConfiguration; }, ) { From 9446b0b12714b3bfbdf0d6802ad21fb1d9450785 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 08:17:07 -0700 Subject: [PATCH 021/146] fix snapshot --- packages/multichain/src/index.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index ffb2b2b8b76..4bae121c2df 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -16,12 +16,6 @@ describe('@metamask/multichain', () => { "multichainMethodCallValidatorMiddleware", "MultichainMiddlewareManager", "MultichainSubscriptionManager", - "Caip25CaveatType", - "Caip25CaveatFactoryFn", - "Caip25EndowmentPermissionName", - "caip25EndowmentBuilder", - "Caip25CaveatMutatorFactories", - "removeScope", "assertScopeSupported", "assertScopesSupported", "validateAndFlattenScopes", @@ -38,6 +32,12 @@ describe('@metamask/multichain', () => { "flattenMergeScopes", "isValidScope", "validateScopes", + "Caip25CaveatType", + "Caip25CaveatFactoryFn", + "Caip25EndowmentPermissionName", + "caip25EndowmentBuilder", + "Caip25CaveatMutatorFactories", + "removeScope", "KnownWalletRpcMethods", "KnownRpcMethods", "KnownWalletNamespaceRpcMethods", From 941849da0e93d4be7da0e771ffa464a957dba306 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 08:31:08 -0700 Subject: [PATCH 022/146] add KnownWalletScopeString enum --- packages/multichain/jest.config.js | 2 +- .../caip-permission-adapter-eth-accounts.ts | 17 ++++++----------- .../caip-permission-adapter-middleware.ts | 4 ++-- .../caip-permission-adapter-permittedChains.ts | 5 +++-- packages/multichain/src/index.test.ts | 1 + packages/multichain/src/scope/types.ts | 4 ++++ 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js index 2f651a645ea..0413429bc38 100644 --- a/packages/multichain/jest.config.js +++ b/packages/multichain/jest.config.js @@ -17,7 +17,7 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 83.05, + branches: 82.95, functions: 87.37, lines: 86.65, statements: 87.09, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 5646bab107a..375e483c5e9 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -8,15 +8,14 @@ import { import type { Caip25CaveatValue } from '../caip25Permission'; import { mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; -import { parseScopeString } from '../scope/types'; +import { KnownWalletScopeString, parseScopeString } from '../scope/types'; const isEip155ScopeString = (scopeString: ScopeString) => { - const { namespace, reference } = parseScopeString(scopeString); + const { namespace } = parseScopeString(scopeString); return ( namespace === KnownCaipNamespace.Eip155 || - (namespace === KnownCaipNamespace.Wallet && - reference === KnownCaipNamespace.Eip155) + scopeString === KnownWalletScopeString.Eip155 ); }; @@ -47,10 +46,7 @@ const setEthAccountsForScopesObject = ( const updatedScopesObject: ScopesObject = {}; Object.entries(scopesObject).forEach(([scopeString, scopeObject]) => { - const { namespace, reference } = parseScopeString(scopeString); - - const isWalletNamespace = - namespace === KnownCaipNamespace.Wallet && reference === undefined; + const isWalletNamespace = scopeString === KnownCaipNamespace.Wallet if ( !isEip155ScopeString(scopeString as ScopeString) && @@ -63,7 +59,7 @@ const setEthAccountsForScopesObject = ( const caipAccounts = accounts.map( (account) => (isWalletNamespace - ? `wallet:eip155:${account}` + ? `${KnownWalletScopeString.Eip155}:${account}` : `${scopeString}:${account}`) as CaipAccountId, ); @@ -76,7 +72,6 @@ const setEthAccountsForScopesObject = ( return updatedScopesObject; }; -// This helper must be called with existing eip155 scopes export const setEthAccounts = ( caip25CaveatValue: Caip25CaveatValue, accounts: Hex[], @@ -93,7 +88,7 @@ export const setEthAccounts = ( methods: [], notifications: [], }, - 'wallet:eip155': { + [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], }, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 811978697f3..865a4cccfcb 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -12,7 +12,7 @@ import { Caip25EndowmentPermissionName, } from '../caip25Permission'; import { mergeScopes } from '../scope/transform'; -import type { ScopeString } from '../scope/types'; +import { KnownWalletScopeString, type ScopeString } from '../scope/types'; /** * Middleware to handle CAIP-25 permission requests. @@ -70,7 +70,7 @@ export async function caipPermissionAdapterMiddleware( if ( !scopesObject[scope]?.methods?.includes(method) && - !scopesObject['wallet:eip155']?.methods?.includes(method) && + !scopesObject[KnownWalletScopeString.Eip155]?.methods?.includes(method) && !scopesObject.wallet?.methods?.includes(method) ) { return end(providerErrors.unauthorized()); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index c0042dbfe96..74e6b5a5556 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,13 +3,14 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownNotifications, KnownRpcMethods, + KnownWalletScopeString, parseScopeString, } from '../scope/types'; +import { mergeScopes } from '../scope/transform'; export const getPermittedEthChainIds = ( caip25CaveatValue: Caip25CaveatValue, @@ -45,7 +46,7 @@ export const addPermittedEthChainId = ( return { ...caip25CaveatValue, optionalScopes: { - 'wallet:eip155': { + [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], }, diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 4bae121c2df..9afd6a57221 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -38,6 +38,7 @@ describe('@metamask/multichain', () => { "caip25EndowmentBuilder", "Caip25CaveatMutatorFactories", "removeScope", + "KnownWalletScopeString", "KnownWalletRpcMethods", "KnownRpcMethods", "KnownWalletNamespaceRpcMethods", diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index c899fa8a40e..16633b63e7e 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -12,6 +12,10 @@ import { parseCaipChainId, } from '@metamask/utils'; +export enum KnownWalletScopeString { + Eip155 = "wallet:eip155", +} + export type NonWalletKnownCaipNamespace = Extract< KnownCaipNamespace, KnownCaipNamespace.Eip155 From a250de21f9e0fdb55f0b4a3bcc90298628d73979 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 09:32:37 -0700 Subject: [PATCH 023/146] stop upserting wallet scope in setEthAccounts() --- ...ip-permission-adapter-eth-accounts.test.ts | 30 +------------------ .../caip-permission-adapter-eth-accounts.ts | 6 +--- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index 76fe6d28802..427034e46c7 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -47,11 +47,6 @@ describe('CAIP-25 eth_accounts adapters', () => { notifications: [], accounts: ['wallet:eip155:0x5'], }, - wallet: { - methods: [], - notifications: [], - accounts: ['wallet:eip155:0x6'], - }, }, isMultichainOrigin: false, }); @@ -63,7 +58,6 @@ describe('CAIP-25 eth_accounts adapters', () => { '0x3', '0x100', '0x5', - '0x6', ]); }); }); @@ -109,10 +103,6 @@ describe('CAIP-25 eth_accounts adapters', () => { methods: [], notifications: [], }, - wallet: { - methods: [], - notifications: [], - }, }, isMultichainOrigin: false, }; @@ -163,21 +153,12 @@ describe('CAIP-25 eth_accounts adapters', () => { 'wallet:eip155:0x3', ], }, - wallet: { - methods: [], - notifications: [], - accounts: [ - 'wallet:eip155:0x1', - 'wallet:eip155:0x2', - 'wallet:eip155:0x3', - ], - }, }, isMultichainOrigin: false, }); }); - it('returns a CAIP-25 caveat value with "wallet" and "wallet:eip155" scopes with CAIP-10 account addresses formed from the accounts param when the "wallet" or "wallet:eip155" are not defined in optional scopes', () => { + it('returns a CAIP-25 caveat value with upserted "wallet:eip155" optional scope with CAIP-10 account addresses formed from the accounts param', () => { const input: Caip25CaveatValue = { requiredScopes: {}, optionalScopes: {}, @@ -188,15 +169,6 @@ describe('CAIP-25 eth_accounts adapters', () => { expect(result).toStrictEqual({ requiredScopes: {}, optionalScopes: { - wallet: { - methods: [], - notifications: [], - accounts: [ - 'wallet:eip155:0x1', - 'wallet:eip155:0x2', - 'wallet:eip155:0x3', - ], - }, 'wallet:eip155': { methods: [], notifications: [], diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 375e483c5e9..52e61aacc1d 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -46,7 +46,7 @@ const setEthAccountsForScopesObject = ( const updatedScopesObject: ScopesObject = {}; Object.entries(scopesObject).forEach(([scopeString, scopeObject]) => { - const isWalletNamespace = scopeString === KnownCaipNamespace.Wallet + const isWalletNamespace = scopeString === KnownCaipNamespace.Wallet; if ( !isEip155ScopeString(scopeString as ScopeString) && @@ -84,10 +84,6 @@ export const setEthAccounts = ( ), optionalScopes: setEthAccountsForScopesObject( { - wallet: { - methods: [], - notifications: [], - }, [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], From aa7ba39a6e141a09bdec32a296ff3c96a68dba9b Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 09:32:44 -0700 Subject: [PATCH 024/146] lint --- packages/multichain/jest.config.js | 2 +- .../src/adapters/caip-permission-adapter-permittedChains.ts | 4 ++-- packages/multichain/src/scope/types.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js index 0413429bc38..1cadcfe8b28 100644 --- a/packages/multichain/jest.config.js +++ b/packages/multichain/jest.config.js @@ -17,7 +17,7 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 82.95, + branches: 82.38, functions: 87.37, lines: 86.65, statements: 87.09, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 74e6b5a5556..b5d6cdd1f47 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,6 +3,7 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownNotifications, @@ -10,7 +11,6 @@ import { KnownWalletScopeString, parseScopeString, } from '../scope/types'; -import { mergeScopes } from '../scope/transform'; export const getPermittedEthChainIds = ( caip25CaveatValue: Caip25CaveatValue, @@ -46,7 +46,7 @@ export const addPermittedEthChainId = ( return { ...caip25CaveatValue, optionalScopes: { - [KnownWalletScopeString.Eip155]: { + [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], }, diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index 16633b63e7e..d9c40b86521 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -13,7 +13,7 @@ import { } from '@metamask/utils'; export enum KnownWalletScopeString { - Eip155 = "wallet:eip155", + Eip155 = 'wallet:eip155', } export type NonWalletKnownCaipNamespace = Extract< From 8415be6ec267fcd4f8c9f9df77bb2adaf6f0a476 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 09:44:01 -0700 Subject: [PATCH 025/146] update removeScope mutator to not revoke permission if requiredScope is removed --- .../multichain/src/caip25Permission.test.ts | 23 ------------------- packages/multichain/src/caip25Permission.ts | 8 +------ 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index af1b92745c6..417e342e80c 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -90,29 +90,6 @@ describe('endowment:caip25', () => { }); }); - it('can revoke the entire permission when a requiredScope is removed', () => { - const ethereumGoerliCaveat = { - requiredScopes: { - 'eip155:1': { - methods: ['eth_call'], - notifications: ['chainChanged'], - }, - }, - optionalScopes: { - 'eip155:5': { - methods: ['eth_call'], - notifications: ['accountsChanged'], - }, - }, - sessionProperties: {}, - isMultichainOrigin: true, - }; - const result = removeScope('eip155:1', ethereumGoerliCaveat); - expect(result).toStrictEqual({ - operation: CaveatMutatorOperation.RevokePermission, - }); - }); - it('can noop when nothing is removed', () => { const ethereumGoerliCaveat = { requiredScopes: { diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index cbf6bf39323..f92456f5284 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -247,13 +247,7 @@ export function removeScope( newOptionalScopes.length !== Object.keys(caip25CaveatValue.optionalScopes).length; - if (requiredScopesRemoved) { - return { - operation: CaveatMutatorOperation.RevokePermission, - }; - } - - if (optionalScopesRemoved) { + if (requiredScopesRemoved || optionalScopesRemoved) { return { operation: CaveatMutatorOperation.UpdateValue, value: { From c7f510ea3bd3219ae6a3a517e00412139e479f62 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 10:00:07 -0700 Subject: [PATCH 026/146] Fix specificationBuilder jsdoc and typing --- .../multichain/src/caip25Permission.test.ts | 4 +++- packages/multichain/src/caip25Permission.ts | 23 ++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index 417e342e80c..982a1434c95 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -222,7 +222,9 @@ describe('endowment:caip25', () => { describe('permission validator', () => { const findNetworkClientIdByChainId = jest.fn(); const { validator } = caip25EndowmentBuilder.specificationBuilder({ - findNetworkClientIdByChainId, + methodHooks: { + findNetworkClientIdByChainId, + }, }); it('throws an error if there is not exactly one caveat', () => { diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index f92456f5284..8345590f458 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -53,24 +53,25 @@ type Caip25EndowmentSpecification = ValidPermissionSpecification<{ allowedCaveats: Readonly> | null; }>; +type Caip25EndowmentSpecificationBuilderOptions = { + methodHooks: { + findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId; + }; +}; + /** - * `endowment:caip25` returns nothing atm; + * Helper that returns a `endowment:caip25` specification that + * can be passed into the PermissionController constructor. * * @param builderOptions - The specification builder options. - * @param builderOptions.findNetworkClientIdByChainId - The hook to find the networkClientId for a chainId. + * @param builderOptions.methodHooks - The RPC method hooks needed by the method implementation. * @returns The specification for the `caip25` endowment. */ const specificationBuilder: PermissionSpecificationBuilder< PermissionType.Endowment, - // TODO: FIX THIS - // eslint-disable-next-line @typescript-eslint/no-explicit-any - any, + Caip25EndowmentSpecificationBuilderOptions, Caip25EndowmentSpecification -> = ({ - findNetworkClientIdByChainId, -}: { - findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId; -}) => { +> = ({ methodHooks }: Caip25EndowmentSpecificationBuilderOptions) => { return { permissionType: PermissionType.Endowment, targetName: Caip25EndowmentPermissionName, @@ -107,7 +108,7 @@ const specificationBuilder: PermissionSpecificationBuilder< const isChainIdSupported = (chainId: Hex) => { try { - findNetworkClientIdByChainId(chainId); + methodHooks.findNetworkClientIdByChainId(chainId); return true; } catch (err) { return false; From 4afa8f81bd022e0c7282c6bc88c13f66edab4899 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 10:02:47 -0700 Subject: [PATCH 027/146] Fix caip25permission type --- packages/multichain/src/caip25Permission.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index 8345590f458..0e5e1636685 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -88,9 +88,8 @@ const specificationBuilder: PermissionSpecificationBuilder< ); } - // TODO: FIX THIS TYPE const { requiredScopes, optionalScopes, isMultichainOrigin } = ( - caip25Caveat as unknown as { value: Caip25CaveatValue } + caip25Caveat.value as { value: Caip25CaveatValue } ).value; if ( From 597e837720641ec9d567622e2a61343aaa762b55 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 10:15:20 -0700 Subject: [PATCH 028/146] Fix caip25permission type --- packages/multichain/src/caip25Permission.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index 0e5e1636685..dc1b9000921 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -88,9 +88,8 @@ const specificationBuilder: PermissionSpecificationBuilder< ); } - const { requiredScopes, optionalScopes, isMultichainOrigin } = ( - caip25Caveat.value as { value: Caip25CaveatValue } - ).value; + const { requiredScopes, optionalScopes, isMultichainOrigin } = + caip25Caveat.value as Caip25CaveatValue; if ( !requiredScopes || From 187218863d0f4c1bca9eab79f7b085a3f443cd76 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 15 Oct 2024 13:32:21 -0500 Subject: [PATCH 029/146] small dry todo fix --- .../src/TokenDetectionController.ts | 26 ++++--------------- packages/controller-utils/src/index.ts | 1 + packages/controller-utils/src/util.test.ts | 26 +++++++++++++++++++ packages/controller-utils/src/util.ts | 17 ++++++++++++ packages/multichain/src/scope/supported.ts | 17 +----------- 5 files changed, 50 insertions(+), 37 deletions(-) diff --git a/packages/assets-controllers/src/TokenDetectionController.ts b/packages/assets-controllers/src/TokenDetectionController.ts index 2459baea38f..76400bc7ccc 100644 --- a/packages/assets-controllers/src/TokenDetectionController.ts +++ b/packages/assets-controllers/src/TokenDetectionController.ts @@ -9,7 +9,11 @@ import type { ControllerStateChangeEvent, } from '@metamask/base-controller'; import contractMap from '@metamask/contract-metadata'; -import { ChainId, safelyExecute } from '@metamask/controller-utils'; +import { + ChainId, + safelyExecute, + isEqualCaseInsensitive, +} from '@metamask/controller-utils'; import type { KeyringControllerGetStateAction, KeyringControllerLockEvent, @@ -44,26 +48,6 @@ import type { const DEFAULT_INTERVAL = 180000; -/** - * Compare 2 given strings and return boolean - * eg: "foo" and "FOO" => true - * eg: "foo" and "bar" => false - * eg: "foo" and 123 => false - * - * @param value1 - first string to compare - * @param value2 - first string to compare - * @returns true if 2 strings are identical when they are lowercase - */ -export function isEqualCaseInsensitive( - value1: string, - value2: string, -): boolean { - if (typeof value1 !== 'string' || typeof value2 !== 'string') { - return false; - } - return value1.toLowerCase() === value2.toLowerCase(); -} - type LegacyToken = { name: string; logo: `${string}.svg`; diff --git a/packages/controller-utils/src/index.ts b/packages/controller-utils/src/index.ts index 265872e6204..3d35d62c0a0 100644 --- a/packages/controller-utils/src/index.ts +++ b/packages/controller-utils/src/index.ts @@ -27,6 +27,7 @@ export { toChecksumHexAddress, toHex, weiHexToGweiDec, + isEqualCaseInsensitive, } from './util'; export * from './types'; export * from './siwe'; diff --git a/packages/controller-utils/src/util.test.ts b/packages/controller-utils/src/util.test.ts index 71dd33e90d6..3126fb7ef12 100644 --- a/packages/controller-utils/src/util.test.ts +++ b/packages/controller-utils/src/util.test.ts @@ -611,3 +611,29 @@ describe('util', () => { }); }); }); + +describe('isEqualCaseInsensitive', () => { + it('returns false for non-string values', () => { + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(null, 'test')).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive('test', null)).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(5, 'test')).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive('test', 5)).toBe(false); + }); + + it('returns false for strings that are not equal', () => { + expect(util.isEqualCaseInsensitive('test', 'test1')).toBe(false); + expect(util.isEqualCaseInsensitive('test1', 'test')).toBe(false); + }); + + it('returns true for strings that are equal', () => { + expect(util.isEqualCaseInsensitive('test', 'TEST')).toBe(true); + expect(util.isEqualCaseInsensitive('test', 'test')).toBe(true); + expect(util.isEqualCaseInsensitive('TEST', 'TEST')).toBe(true); + expect(util.isEqualCaseInsensitive('test', 'Test')).toBe(true); + expect(util.isEqualCaseInsensitive('Test', 'test')).toBe(true); + }); +}); diff --git a/packages/controller-utils/src/util.ts b/packages/controller-utils/src/util.ts index 4d14f71e6f9..4d53b069d9e 100644 --- a/packages/controller-utils/src/util.ts +++ b/packages/controller-utils/src/util.ts @@ -619,3 +619,20 @@ function logOrRethrowError(error: unknown, codesToCatch: number[] = []) { throw error; } } + +/** + * Checks if two strings are equal, ignoring case. + * + * @param value1 - The first string to compare. + * @param value2 - The second string to compare. + * @returns `true` if the strings are equal, ignoring case; otherwise, `false`. + */ +export function isEqualCaseInsensitive( + value1: string, + value2: string, +): boolean { + if (typeof value1 !== 'string' || typeof value2 !== 'string') { + return false; + } + return value1.toLowerCase() === value2.toLowerCase(); +} diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts index 364e2cd249a..52f351ea6c3 100644 --- a/packages/multichain/src/scope/supported.ts +++ b/packages/multichain/src/scope/supported.ts @@ -1,4 +1,4 @@ -import { toHex } from '@metamask/controller-utils'; +import { toHex, isEqualCaseInsensitive } from '@metamask/controller-utils'; import type { CaipAccountId, Hex } from '@metamask/utils'; import { isCaipChainId, @@ -17,21 +17,6 @@ import { parseScopeString, } from './types'; -// TODO Maybe this gets DRY'ed into utils?.. It's used in TokenDetectionController too -/** - * Checks if two strings are equal, ignoring case. - * - * @param value1 - The first string to compare. - * @param value2 - The second string to compare. - * @returns `true` if the strings are equal, ignoring case; otherwise, `false`. - */ -function isEqualCaseInsensitive(value1: string, value2: string): boolean { - if (typeof value1 !== 'string' || typeof value2 !== 'string') { - return false; - } - return value1.toLowerCase() === value2.toLowerCase(); -} - export const isSupportedScopeString = ( scopeString: string, isChainIdSupported: (chainId: Hex) => boolean, From c5d80056f20a39d67b8ef6935440936ba57cae3b Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 15 Oct 2024 13:37:13 -0500 Subject: [PATCH 030/146] another small dry --- .../adapters/caip-permission-adapter-eth-accounts.ts | 4 ++-- .../caip-permission-adapter-permittedChains.ts | 4 ++-- packages/multichain/src/scope/transform.ts | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 52e61aacc1d..e0ef4038bfa 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -6,7 +6,7 @@ import { } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; +import { getUniqueArrayItems, mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownWalletScopeString, parseScopeString } from '../scope/types'; @@ -36,7 +36,7 @@ export const getEthAccounts = (caip25CaveatValue: Caip25CaveatValue) => { }); }); - return Array.from(new Set(ethAccounts)); + return getUniqueArrayItems(ethAccounts); }; const setEthAccountsForScopesObject = ( diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index b5d6cdd1f47..25bd63a208c 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,7 +3,7 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; +import { getUniqueArrayItems, mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; import { KnownNotifications, @@ -28,7 +28,7 @@ export const getPermittedEthChainIds = ( } }); - return Array.from(new Set(ethChainIds)); + return getUniqueArrayItems(ethChainIds); }; export const addPermittedEthChainId = ( diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts index a5bb2e9070f..72d90bbb7a4 100644 --- a/packages/multichain/src/scope/transform.ts +++ b/packages/multichain/src/scope/transform.ts @@ -10,14 +10,13 @@ import type { } from './types'; import { parseScopeString } from './types'; -// TODO: DRY THIS /** * Returns a list of unique items * * @param list - The list of items to filter * @returns A list of unique items */ -function unique(list: Value[]): Value[] { +export function getUniqueArrayItems(list: Value[]): Value[] { return Array.from(new Set(list)); } @@ -56,28 +55,28 @@ export const mergeScopeObject = ( ) => { const mergedScopeObject: ScopeObject = { methods: unique([...scopeObjectA.methods, ...scopeObjectB.methods]), - notifications: unique([ + notifications: getUniqueArrayItems([ ...scopeObjectA.notifications, ...scopeObjectB.notifications, ]), }; if (scopeObjectA.accounts || scopeObjectB.accounts) { - mergedScopeObject.accounts = unique([ + mergedScopeObject.accounts = getUniqueArrayItems([ ...(scopeObjectA.accounts ?? []), ...(scopeObjectB.accounts ?? []), ]); } if (scopeObjectA.rpcDocuments || scopeObjectB.rpcDocuments) { - mergedScopeObject.rpcDocuments = unique([ + mergedScopeObject.rpcDocuments = getUniqueArrayItems([ ...(scopeObjectA.rpcDocuments ?? []), ...(scopeObjectB.rpcDocuments ?? []), ]); } if (scopeObjectA.rpcEndpoints || scopeObjectB.rpcEndpoints) { - mergedScopeObject.rpcEndpoints = unique([ + mergedScopeObject.rpcEndpoints = getUniqueArrayItems([ ...(scopeObjectA.rpcEndpoints ?? []), ...(scopeObjectB.rpcEndpoints ?? []), ]); From 54f7c497e47d7770d19ca54f5a4cc88655c978a2 Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 15 Oct 2024 16:01:25 -0400 Subject: [PATCH 031/146] Added handler wrappers to better integrate with existing middleware (#4796) Add handler wrappers to better integrate with existing middleware in extension --------- Co-authored-by: Jiexi Luan --- .../src/handlers/wallet-getSession.test.ts | 4 ++-- .../src/handlers/wallet-getSession.ts | 10 +++++++++- .../src/handlers/wallet-invokeMethod.test.ts | 18 ++++++++++++------ .../src/handlers/wallet-invokeMethod.ts | 11 ++++++++++- .../src/handlers/wallet-revokeSession.test.ts | 4 ++-- .../src/handlers/wallet-revokeSession.ts | 9 ++++++++- packages/multichain/src/index.test.ts | 6 +++--- packages/multichain/src/index.ts | 6 +++--- packages/multichain/src/scope/transform.ts | 9 ++++++--- 9 files changed, 55 insertions(+), 22 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index ebee666967b..68c6044119f 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -4,7 +4,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { walletGetSessionHandler } from './wallet-getSession'; +import { walletGetSession } from './wallet-getSession'; const baseRequest: JsonRpcRequest & { origin: string } = { origin: 'http://test.com', @@ -49,7 +49,7 @@ const createMockedHandler = () => { jsonrpc: '2.0' as const, }; const handler = (request: JsonRpcRequest & { origin: string }) => - walletGetSessionHandler(request, response, next, end, { + walletGetSession.implementation(request, response, next, end, { getCaveat, }); diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 13c9e4f0170..ad3e4e5569b 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -19,7 +19,7 @@ import type { ScopesObject } from '../scope/types'; * @param hooks - The hooks object. * @param hooks.getCaveat - Function to retrieve a caveat. */ -export async function walletGetSessionHandler( +async function walletGetSessionHandler( request: JsonRpcRequest & { origin: string }, response: JsonRpcSuccess<{ sessionScopes: ScopesObject }>, _next: () => void, @@ -56,3 +56,11 @@ export async function walletGetSessionHandler( }; return end(); } + +export const walletGetSession = { + methodNames: ['wallet_getSession'], + implementation: walletGetSessionHandler, + hookNames: { + getCaveat: true, + }, +}; diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index ebffb0ece8b..fce6550e72e 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -5,7 +5,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { walletInvokeMethodHandler } from './wallet-invokeMethod'; +import { walletInvokeMethod } from './wallet-invokeMethod'; const createMockedRequest = () => ({ jsonrpc: '2.0' as const, @@ -60,11 +60,17 @@ const createMockedHandler = () => { .fn() .mockReturnValue('selectedNetworkClientId'); const handler = (request: JsonRpcRequest & { origin: string }) => - walletInvokeMethodHandler(request, { jsonrpc: '2.0', id: 1 }, next, end, { - getCaveat, - findNetworkClientIdByChainId, - getSelectedNetworkClientId, - }); + walletInvokeMethod.implementation( + request, + { jsonrpc: '2.0', id: 1 }, + next, + end, + { + getCaveat, + findNetworkClientIdByChainId, + getSelectedNetworkClientId, + }, + ); return { next, diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 239d65195b4..3df3ca8346f 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -28,7 +28,7 @@ import { parseScopeString } from '../scope/types'; * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId. * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. */ -export async function walletInvokeMethodHandler( +async function walletInvokeMethodHandler( request: JsonRpcRequest & { origin: string }, _response: PendingJsonRpcResponse, next: () => void, @@ -109,3 +109,12 @@ export async function walletInvokeMethodHandler( }); return next(); } +export const walletInvokeMethod = { + methodNames: ['wallet_invokeMethod'], + implementation: walletInvokeMethodHandler, + hookNames: { + getCaveat: true, + findNetworkClientIdByChainId: true, + getSelectedNetworkClientId: true, + }, +}; diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.ts b/packages/multichain/src/handlers/wallet-revokeSession.test.ts index 695d0eb4304..e11b89f42c2 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.test.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.ts @@ -6,7 +6,7 @@ import { rpcErrors } from '@metamask/rpc-errors'; import type { JsonRpcRequest } from '@metamask/utils'; import { Caip25EndowmentPermissionName } from '../caip25Permission'; -import { walletRevokeSessionHandler } from './wallet-revokeSession'; +import { walletRevokeSession } from './wallet-revokeSession'; const baseRequest: JsonRpcRequest & { origin: string } = { origin: 'http://test.com', @@ -26,7 +26,7 @@ const createMockedHandler = () => { jsonrpc: '2.0' as const, }; const handler = (request: JsonRpcRequest & { origin: string }) => - walletRevokeSessionHandler(request, response, next, end, { + walletRevokeSession.implementation(request, response, next, end, { revokePermission, }); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 1aec0b7245b..51e31073f0d 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -21,7 +21,7 @@ import { Caip25EndowmentPermissionName } from '../caip25Permission'; * @param hooks - The hooks object. * @param hooks.revokePermission - The revokePermission function. */ -export async function walletRevokeSessionHandler( +async function walletRevokeSessionHandler( request: JsonRpcRequest & { origin: string }, response: JsonRpcSuccess, _next: JsonRpcEngineNextCallback, @@ -45,3 +45,10 @@ export async function walletRevokeSessionHandler( response.result = true; return end(); } +export const walletRevokeSession = { + methodNames: ['wallet_revokeSession'], + implementation: walletRevokeSessionHandler, + hookNames: { + revokePermission: true, + }, +}; diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 9afd6a57221..cca93222f71 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -10,9 +10,9 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", - "walletGetSessionHandler", - "walletInvokeMethodHandler", - "walletRevokeSessionHandler", + "walletGetSession", + "walletInvokeMethod", + "walletRevokeSession", "multichainMethodCallValidatorMiddleware", "MultichainMiddlewareManager", "MultichainSubscriptionManager", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 55a4cd38221..9211d699670 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -9,9 +9,9 @@ export { setPermittedEthChainIds, } from './adapters/caip-permission-adapter-permittedChains'; -export { walletGetSessionHandler } from './handlers/wallet-getSession'; -export { walletInvokeMethodHandler } from './handlers/wallet-invokeMethod'; -export { walletRevokeSessionHandler } from './handlers/wallet-revokeSession'; +export { walletGetSession } from './handlers/wallet-getSession'; +export { walletInvokeMethod } from './handlers/wallet-invokeMethod'; +export { walletRevokeSession } from './handlers/wallet-revokeSession'; export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator'; export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager'; diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts index 72d90bbb7a4..5aeecc6930e 100644 --- a/packages/multichain/src/scope/transform.ts +++ b/packages/multichain/src/scope/transform.ts @@ -16,9 +16,9 @@ import { parseScopeString } from './types'; * @param list - The list of items to filter * @returns A list of unique items */ -export function getUniqueArrayItems(list: Value[]): Value[] { +export const getUniqueArrayItems = (list: Value[]): Value[] => { return Array.from(new Set(list)); -} +}; /** * Flattens a ScopeString and ScopeObject into a separate @@ -54,7 +54,10 @@ export const mergeScopeObject = ( scopeObjectB: ScopeObject, ) => { const mergedScopeObject: ScopeObject = { - methods: unique([...scopeObjectA.methods, ...scopeObjectB.methods]), + methods: getUniqueArrayItems([ + ...scopeObjectA.methods, + ...scopeObjectB.methods, + ]), notifications: getUniqueArrayItems([ ...scopeObjectA.notifications, ...scopeObjectB.notifications, From ada451daaff2700b7acc1916b1c5c4d48310e40e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 13:52:55 -0700 Subject: [PATCH 032/146] change subscriptionManager require to import --- .../src/middlewares/MultichainSubscriptionManager.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 0fed86cfd92..fa5b1397a26 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -4,6 +4,7 @@ import SafeEventEmitter from '@metamask/safe-event-emitter'; import type { CaipChainId, Hex } from '@metamask/utils'; import { parseCaipChainId } from '@metamask/utils'; import type EventEmitter from 'events'; +import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; import type { ExternalScopeString } from '../scope/types'; @@ -30,9 +31,6 @@ type SubscriptionEntry = SubscriptionKey & { subscriptionManager: SubscriptionManager; }; -// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); - type MultichainSubscriptionManagerOptions = { findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; getNetworkClientById: NetworkController['getNetworkClientById']; From 2322e39df6590dae6514ab14e37dbd3f58a1f2ed Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 15 Oct 2024 13:59:10 -0700 Subject: [PATCH 033/146] lint --- .../multichain/src/middlewares/MultichainSubscriptionManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index fa5b1397a26..6494ed24a59 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -1,10 +1,10 @@ import { toHex } from '@metamask/controller-utils'; +import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; import type { NetworkController } from '@metamask/network-controller'; import SafeEventEmitter from '@metamask/safe-event-emitter'; import type { CaipChainId, Hex } from '@metamask/utils'; import { parseCaipChainId } from '@metamask/utils'; import type EventEmitter from 'events'; -import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; import type { ExternalScopeString } from '../scope/types'; From 00a41cb81920d2cfd6af1b64fce60649e0c02528 Mon Sep 17 00:00:00 2001 From: jiexi Date: Wed, 16 Oct 2024 12:37:52 -0700 Subject: [PATCH 034/146] Jl/caip multichain/update scope object account types (#4803) ## Explanation * Make `accounts` required on `ScopeObject` * Make `flattenScope` also add empty `accounts` array if missing * Rename `flattenScope` to `normalizeScope` * Rename `validateAndFlattenScopes` to `validateAndNormalizeScopes` * Rename `flattenMergeScopes` to `normalizeAndMergeScopes` ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- ...ip-permission-adapter-eth-accounts.test.ts | 3 + .../caip-permission-adapter-eth-accounts.ts | 1 + ...caip-permission-adapter-middleware.test.ts | 5 ++ ...permission-adapter-permittedChains.test.ts | 11 +++ ...caip-permission-adapter-permittedChains.ts | 1 + .../multichain/src/caip25Permission.test.ts | 76 +++++++++++-------- packages/multichain/src/caip25Permission.ts | 14 ++-- .../src/handlers/wallet-getSession.test.ts | 7 ++ .../src/handlers/wallet-invokeMethod.test.ts | 5 ++ packages/multichain/src/index.test.ts | 6 +- packages/multichain/src/index.ts | 9 ++- packages/multichain/src/scope/assert.test.ts | 1 + .../src/scope/authorization.test.ts | 36 +++++---- .../multichain/src/scope/authorization.ts | 16 ++-- packages/multichain/src/scope/filter.test.ts | 15 ++++ .../multichain/src/scope/transform.test.ts | 55 +++++++++----- packages/multichain/src/scope/transform.ts | 47 ++++++------ packages/multichain/src/scope/types.ts | 5 +- 18 files changed, 206 insertions(+), 107 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index 427034e46c7..eb559666787 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -36,6 +36,7 @@ describe('CAIP-25 eth_accounts adapters', () => { 'eip155:10': { methods: [], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -93,6 +94,7 @@ describe('CAIP-25 eth_accounts adapters', () => { 'eip155:10': { methods: [], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -102,6 +104,7 @@ describe('CAIP-25 eth_accounts adapters', () => { 'wallet:eip155': { methods: [], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index e0ef4038bfa..6c72f1d07ba 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -87,6 +87,7 @@ export const setEthAccounts = ( [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], + accounts: [], }, ...caip25CaveatValue.optionalScopes, }, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts index ea6318074ab..c044c73b0f0 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts @@ -27,24 +27,29 @@ const createMockedHandler = () => { 'eip155:1': { methods: ['eth_call'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, }, optionalScopes: { 'eip155:1': { methods: ['net_version'], notifications: [], + accounts: [], }, wallet: { methods: ['wallet_watchAsset'], notifications: [], + accounts: [], }, unhandled: { methods: ['foobar'], notifications: [], + accounts: [], }, }, isMultichainOrigin: true, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 2ca86004f3a..4020c2442bf 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -38,6 +38,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'eip155:10': { methods: [], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -72,6 +73,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'wallet:eip155': { methods: [], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, @@ -101,6 +103,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'wallet:eip155': { methods: [], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, @@ -151,6 +154,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'wallet:eip155': { methods: [], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, @@ -246,12 +250,14 @@ describe('CAIP-25 permittedChains adapters', () => { 'bip122:000000000019d6689c085ae165831e93': { methods: [], notifications: [], + accounts: [], }, }, optionalScopes: { 'eip155:1': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -274,12 +280,14 @@ describe('CAIP-25 permittedChains adapters', () => { 'bip122:000000000019d6689c085ae165831e93': { methods: [], notifications: [], + accounts: [], }, }, optionalScopes: { 'eip155:1': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, @@ -300,6 +308,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'eip155:1': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -324,6 +333,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'eip155:1': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, 'eip155:100': { methods: [], @@ -338,6 +348,7 @@ describe('CAIP-25 permittedChains adapters', () => { 'wallet:eip155': { methods: [], notifications: [], + accounts: [], }, }, isMultichainOrigin: false, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 25bd63a208c..6a59efa916f 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -49,6 +49,7 @@ export const addPermittedEthChainId = ( [KnownWalletScopeString.Eip155]: { methods: [], notifications: [], + accounts: [], }, ...caip25CaveatValue.optionalScopes, [scopeString]: { diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index 982a1434c95..818035ff8a5 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -17,7 +17,7 @@ import * as ScopeAssert from './scope/assert'; import * as ScopeAuthorization from './scope/authorization'; jest.mock('./scope/authorization', () => ({ - validateAndFlattenScopes: jest.fn(), + validateAndNormalizeScopes: jest.fn(), })); const MockScopeAuthorization = jest.mocked(ScopeAuthorization); @@ -30,9 +30,9 @@ const { removeAccount } = Caip25CaveatMutatorFactories[Caip25CaveatType]; describe('endowment:caip25', () => { beforeEach(() => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: {}, - flattenedOptionalScopes: {}, + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: {}, + normalizedOptionalScopes: {}, }); }); @@ -64,12 +64,14 @@ describe('endowment:caip25', () => { 'eip155:1': { methods: ['eth_call'], notifications: ['chainChanged'], + accounts: [], }, }, optionalScopes: { 'eip155:5': { methods: ['eth_call'], notifications: ['accountsChanged'], + accounts: [], }, }, sessionProperties: {}, @@ -83,6 +85,7 @@ describe('endowment:caip25', () => { 'eip155:1': { methods: ['eth_call'], notifications: ['chainChanged'], + accounts: [], }, }, optionalScopes: {}, @@ -96,12 +99,14 @@ describe('endowment:caip25', () => { 'eip155:1': { methods: ['eth_call'], notifications: ['chainChanged'], + accounts: [], }, }, optionalScopes: { 'eip155:5': { methods: ['eth_call'], notifications: ['accountsChanged'], + accounts: [], }, }, sessionProperties: {}, @@ -208,6 +213,7 @@ describe('endowment:caip25', () => { 'eip155:5': { methods: ['eth_call'], notifications: ['accountsChanged'], + accounts: [], }, }, isMultichainOrigin: true, @@ -358,7 +364,7 @@ describe('endowment:caip25', () => { ); }); - it('validates and flattens the ScopesObjects', () => { + it('validates and normalizes the ScopesObjects', () => { try { validator({ caveats: [ @@ -392,7 +398,7 @@ describe('endowment:caip25', () => { // noop } expect( - MockScopeAuthorization.validateAndFlattenScopes, + MockScopeAuthorization.validateAndNormalizeScopes, ).toHaveBeenCalledWith( { 'eip155:1': { @@ -411,18 +417,20 @@ describe('endowment:caip25', () => { ); }); - it('asserts the validated and flattened required scopes are supported', () => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: { + it('asserts the validated and normalized required scopes are supported', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { 'eip155:1': { - methods: ['flattened_required'], + methods: ['normalized_required'], notifications: [], + accounts: [], }, }, - flattenedOptionalScopes: { + normalizedOptionalScopes: { 'eip155:1': { - methods: ['flattened_optional'], + methods: ['normalized_optional'], notifications: [], + accounts: [], }, }, }); @@ -461,8 +469,9 @@ describe('endowment:caip25', () => { expect(MockScopeAssert.assertScopesSupported).toHaveBeenCalledWith( { 'eip155:1': { - methods: ['flattened_required'], + methods: ['normalized_required'], notifications: [], + accounts: [], }, }, expect.objectContaining({ @@ -474,18 +483,20 @@ describe('endowment:caip25', () => { expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); - it('asserts the validated and flattened optional scopes are supported', () => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: { + it('asserts the validated and normalized optional scopes are supported', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { 'eip155:1': { - methods: ['flattened_required'], + methods: ['normalized_required'], notifications: [], + accounts: [], }, }, - flattenedOptionalScopes: { + normalizedOptionalScopes: { 'eip155:1': { - methods: ['flattened_optional'], + methods: ['normalized_optional'], notifications: [], + accounts: [], }, }, }); @@ -524,8 +535,9 @@ describe('endowment:caip25', () => { expect(MockScopeAssert.assertScopesSupported).toHaveBeenCalledWith( { 'eip155:1': { - methods: ['flattened_optional'], + methods: ['normalized_optional'], notifications: [], + accounts: [], }, }, expect.objectContaining({ @@ -537,10 +549,10 @@ describe('endowment:caip25', () => { expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); - it('throws if the input requiredScopes does not match the output of validateAndFlattenScopes', () => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: {}, - flattenedOptionalScopes: { + it('throws if the input requiredScopes does not match the output of validateAndNormalizeScopes', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: {}, + normalizedOptionalScopes: { 'eip155:5': { methods: [], notifications: [], @@ -580,16 +592,16 @@ describe('endowment:caip25', () => { }).toThrow(/Expected values to be strictly deep-equal/u); }); - it('throws if the input optionalScopes does not match the output of validateAndFlattenScopes', () => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: { + it('throws if the input optionalScopes does not match the output of validateAndNormalizeScopes', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { 'eip155:1': { methods: ['eth_chainId'], notifications: [], accounts: ['eip155:1:0xdead'], }, }, - flattenedOptionalScopes: {}, + normalizedOptionalScopes: {}, }); expect(() => { validator({ @@ -623,16 +635,16 @@ describe('endowment:caip25', () => { }).toThrow(/Expected values to be strictly deep-equal/u); }); - it('does not throw if the input requiredScopes and optionalScopes ScopesObject are already validated and flattened', () => { - MockScopeAuthorization.validateAndFlattenScopes.mockReturnValue({ - flattenedRequiredScopes: { + it('does not throw if the input requiredScopes and optionalScopes ScopesObject are already validated and normalized', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { 'eip155:1': { methods: ['eth_chainId'], notifications: [], accounts: ['eip155:1:0xdead'], }, }, - flattenedOptionalScopes: { + normalizedOptionalScopes: { 'eip155:5': { methods: [], notifications: [], diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index dc1b9000921..f4f7ec88c18 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -20,7 +20,7 @@ import { strict as assert } from 'assert'; import { cloneDeep, isEqual } from 'lodash'; import { assertScopesSupported } from './scope/assert'; -import { validateAndFlattenScopes } from './scope/authorization'; +import { validateAndNormalizeScopes } from './scope/authorization'; import type { ExternalScopeString, ScopeObject, @@ -101,8 +101,8 @@ const specificationBuilder: PermissionSpecificationBuilder< ); } - const { flattenedRequiredScopes, flattenedOptionalScopes } = - validateAndFlattenScopes(requiredScopes, optionalScopes); + const { normalizedRequiredScopes, normalizedOptionalScopes } = + validateAndNormalizeScopes(requiredScopes, optionalScopes); const isChainIdSupported = (chainId: Hex) => { try { @@ -113,15 +113,15 @@ const specificationBuilder: PermissionSpecificationBuilder< } }; - assertScopesSupported(flattenedRequiredScopes, { + assertScopesSupported(normalizedRequiredScopes, { isChainIdSupported, }); - assertScopesSupported(flattenedOptionalScopes, { + assertScopesSupported(normalizedOptionalScopes, { isChainIdSupported, }); - assert.deepEqual(requiredScopes, flattenedRequiredScopes); - assert.deepEqual(optionalScopes, flattenedOptionalScopes); + assert.deepEqual(requiredScopes, normalizedRequiredScopes); + assert.deepEqual(optionalScopes, normalizedOptionalScopes); }, }; }; diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index 68c6044119f..ca74cc9b909 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -23,20 +23,24 @@ const createMockedHandler = () => { 'eip155:1': { methods: ['eth_call'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, }, optionalScopes: { 'eip155:1': { methods: ['net_version'], notifications: ['chainChanged'], + accounts: [], }, wallet: { methods: ['wallet_watchAsset'], notifications: [], + accounts: [], }, }, }, @@ -95,14 +99,17 @@ describe('wallet_getSession', () => { 'eip155:1': { methods: ['eth_call', 'net_version'], notifications: ['chainChanged'], + accounts: [], }, 'eip155:5': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, wallet: { methods: ['wallet_watchAsset'], notifications: [], + accounts: [], }, }, }); diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index fce6550e72e..208bccc3371 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -32,24 +32,29 @@ const createMockedHandler = () => { 'eip155:1': { methods: ['eth_call'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['eth_chainId'], notifications: [], + accounts: [], }, }, optionalScopes: { 'eip155:1': { methods: ['net_version'], notifications: [], + accounts: [], }, wallet: { methods: ['wallet_watchAsset'], notifications: [], + accounts: [], }, unhandled: { methods: ['foobar'], notifications: [], + accounts: [], }, }, isMultichainOrigin: true, diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index cca93222f71..d06cd6094eb 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -18,7 +18,7 @@ describe('@metamask/multichain', () => { "MultichainSubscriptionManager", "assertScopeSupported", "assertScopesSupported", - "validateAndFlattenScopes", + "validateAndNormalizeScopes", "bucketScopes", "bucketScopesBySupport", "filterScopesSupported", @@ -26,10 +26,10 @@ describe('@metamask/multichain', () => { "isSupportedAccount", "isSupportedMethod", "isSupportedNotification", - "flattenScope", + "normalizeScope", "mergeScopeObject", "mergeScopes", - "flattenMergeScopes", + "normalizeAndMergeScopes", "isValidScope", "validateScopes", "Caip25CaveatType", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 9211d699670..f764ea5b3ec 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -19,7 +19,10 @@ export { MultichainSubscriptionManager } from './middlewares/MultichainSubscript export { assertScopeSupported, assertScopesSupported } from './scope/assert'; export type { Caip25Authorization } from './scope/authorization'; -export { validateAndFlattenScopes, bucketScopes } from './scope/authorization'; +export { + validateAndNormalizeScopes, + bucketScopes, +} from './scope/authorization'; export { bucketScopesBySupport, filterScopesSupported } from './scope/filter'; export * from './scope/types'; export { @@ -29,10 +32,10 @@ export { isSupportedNotification, } from './scope/supported'; export { - flattenScope, + normalizeScope, mergeScopeObject, mergeScopes, - flattenMergeScopes, + normalizeAndMergeScopes, } from './scope/transform'; export { isValidScope, validateScopes } from './scope/validation'; diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 92e936a741b..9b09aa64379 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -14,6 +14,7 @@ const MockSupported = jest.mocked(Supported); const validScopeObject: ScopeObject = { methods: [], notifications: [], + accounts: [], }; describe('Scope Assert', () => { diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 44e6323f388..4c8bc65e7fb 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,4 +1,4 @@ -import { bucketScopes, validateAndFlattenScopes } from './authorization'; +import { bucketScopes, validateAndNormalizeScopes } from './authorization'; import * as Filter from './filter'; import * as Transform from './transform'; import type { ExternalScopeObject } from './types'; @@ -10,7 +10,7 @@ jest.mock('./validation', () => ({ const MockValidation = jest.mocked(Validation); jest.mock('./transform', () => ({ - flattenMergeScopes: jest.fn(), + normalizeAndMergeScopes: jest.fn(), })); const MockTransform = jest.mocked(Transform); @@ -29,10 +29,10 @@ describe('Scope Authorization', () => { jest.resetAllMocks(); }); - describe('validateAndFlattenScopes', () => { + describe('validateAndNormalizeScopes', () => { it('validates the scopes', () => { try { - validateAndFlattenScopes( + validateAndNormalizeScopes( { 'eip155:1': validScopeObject, }, @@ -53,7 +53,7 @@ describe('Scope Authorization', () => { ); }); - it('flatten and merges the validated scopes', () => { + it('normalized and merges the validated scopes', () => { MockValidation.validateScopes.mockReturnValue({ validRequiredScopes: { 'eip155:1': validScopeObject, @@ -63,16 +63,16 @@ describe('Scope Authorization', () => { }, }); - validateAndFlattenScopes({}, {}); - expect(MockTransform.flattenMergeScopes).toHaveBeenCalledWith({ + validateAndNormalizeScopes({}, {}); + expect(MockTransform.normalizeAndMergeScopes).toHaveBeenCalledWith({ 'eip155:1': validScopeObject, }); - expect(MockTransform.flattenMergeScopes).toHaveBeenCalledWith({ + expect(MockTransform.normalizeAndMergeScopes).toHaveBeenCalledWith({ 'eip155:5': validScopeObject, }); }); - it('returns the flattened and merged scopes', () => { + it('returns the normalized and merged scopes', () => { MockValidation.validateScopes.mockReturnValue({ validRequiredScopes: { 'eip155:1': validScopeObject, @@ -81,17 +81,17 @@ describe('Scope Authorization', () => { 'eip155:5': validScopeObject, }, }); - MockTransform.flattenMergeScopes.mockImplementation((value) => ({ + MockTransform.normalizeAndMergeScopes.mockImplementation((value) => ({ ...value, transformed: true, })); - expect(validateAndFlattenScopes({}, {})).toStrictEqual({ - flattenedRequiredScopes: { + expect(validateAndNormalizeScopes({}, {})).toStrictEqual({ + normalizedRequiredScopes: { 'eip155:1': validScopeObject, transformed: true, }, - flattenedOptionalScopes: { + normalizedOptionalScopes: { 'eip155:5': validScopeObject, transformed: true, }, @@ -109,12 +109,14 @@ describe('Scope Authorization', () => { 'mock:A': { methods: [`mock_method_${callCount}`], notifications: [], + accounts: [], }, }, unsupportedScopes: { 'mock:B': { methods: [`mock_method_${callCount}`], notifications: [], + accounts: [], }, }, }; @@ -128,6 +130,7 @@ describe('Scope Authorization', () => { wallet: { methods: [], notifications: [], + accounts: [], }, }, { @@ -141,6 +144,7 @@ describe('Scope Authorization', () => { wallet: { methods: [], notifications: [], + accounts: [], }, }, { @@ -156,6 +160,7 @@ describe('Scope Authorization', () => { wallet: { methods: [], notifications: [], + accounts: [], }, }, { @@ -169,6 +174,7 @@ describe('Scope Authorization', () => { 'mock:B': { methods: [`mock_method_1`], notifications: [], + accounts: [], }, }, { @@ -184,6 +190,7 @@ describe('Scope Authorization', () => { wallet: { methods: [], notifications: [], + accounts: [], }, }, { @@ -196,18 +203,21 @@ describe('Scope Authorization', () => { 'mock:A': { methods: [`mock_method_1`], notifications: [], + accounts: [], }, }, supportableScopes: { 'mock:A': { methods: [`mock_method_2`], notifications: [], + accounts: [], }, }, unsupportableScopes: { 'mock:B': { methods: [`mock_method_2`], notifications: [], + accounts: [], }, }, }); diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index 9b377a8b137..3dcbef7e40d 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,7 +1,7 @@ import type { Hex } from '@metamask/utils'; import { bucketScopesBySupport } from './filter'; -import { flattenMergeScopes } from './transform'; +import { normalizeAndMergeScopes } from './transform'; import type { ExternalScopesObject, ScopesObject } from './types'; import { validateScopes } from './validation'; @@ -18,24 +18,24 @@ export type Caip25Authorization = sessionProperties?: Record; }); -export const validateAndFlattenScopes = ( +export const validateAndNormalizeScopes = ( requiredScopes: ExternalScopesObject, optionalScopes: ExternalScopesObject, ): { - flattenedRequiredScopes: ScopesObject; - flattenedOptionalScopes: ScopesObject; + normalizedRequiredScopes: ScopesObject; + normalizedOptionalScopes: ScopesObject; } => { const { validRequiredScopes, validOptionalScopes } = validateScopes( requiredScopes, optionalScopes, ); - const flattenedRequiredScopes = flattenMergeScopes(validRequiredScopes); - const flattenedOptionalScopes = flattenMergeScopes(validOptionalScopes); + const normalizedRequiredScopes = normalizeAndMergeScopes(validRequiredScopes); + const normalizedOptionalScopes = normalizeAndMergeScopes(validOptionalScopes); return { - flattenedRequiredScopes, - flattenedOptionalScopes, + normalizedRequiredScopes, + normalizedOptionalScopes, }; }; diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts index cf7c4925834..c49c7397864 100644 --- a/packages/multichain/src/scope/filter.test.ts +++ b/packages/multichain/src/scope/filter.test.ts @@ -20,10 +20,12 @@ describe('filter', () => { 'eip155:1': { methods: ['a'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }, { isChainIdSupported }, @@ -34,6 +36,7 @@ describe('filter', () => { { methods: ['a'], notifications: [], + accounts: [], }, { isChainIdSupported }, ); @@ -42,6 +45,7 @@ describe('filter', () => { { methods: ['b'], notifications: [], + accounts: [], }, { isChainIdSupported }, ); @@ -60,10 +64,12 @@ describe('filter', () => { 'eip155:1': { methods: ['a'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }, { isChainIdSupported }, @@ -72,6 +78,7 @@ describe('filter', () => { 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }); }); @@ -86,10 +93,12 @@ describe('filter', () => { 'eip155:1': { methods: ['a'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }, { isChainIdSupported }, @@ -100,6 +109,7 @@ describe('filter', () => { { methods: ['a'], notifications: [], + accounts: [], }, { isChainIdSupported }, ); @@ -108,6 +118,7 @@ describe('filter', () => { { methods: ['b'], notifications: [], + accounts: [], }, { isChainIdSupported }, ); @@ -126,10 +137,12 @@ describe('filter', () => { 'eip155:1': { methods: ['a'], notifications: [], + accounts: [], }, 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }, { isChainIdSupported }, @@ -139,12 +152,14 @@ describe('filter', () => { 'eip155:5': { methods: ['b'], notifications: [], + accounts: [], }, }, unsupportedScopes: { 'eip155:1': { methods: ['a'], notifications: [], + accounts: [], }, }, }); diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index acfc694e7db..afdd3ae2a35 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -1,34 +1,46 @@ import { - flattenScope, + normalizeScope, mergeScopes, mergeScopeObject, - flattenMergeScopes, + normalizeAndMergeScopes, } from './transform'; -import type { ExternalScopeObject } from './types'; +import type { ExternalScopeObject, ScopeObject } from './types'; -const validScopeObject: ExternalScopeObject = { +const externalScopeObject: ExternalScopeObject = { methods: [], notifications: [], }; +const validScopeObject: ScopeObject = { + methods: [], + notifications: [], + accounts: [], +}; + describe('Scope Transform', () => { - describe('flattenScope', () => { - it('returns the scope as is when the scopeString is chain scoped', () => { - expect(flattenScope('eip155:1', validScopeObject)).toStrictEqual({ + describe('normalizeScope', () => { + it('returns the scope with empty accounts array when the scopeString is chain scoped when accounts are not defined', () => { + expect(normalizeScope('eip155:1', externalScopeObject)).toStrictEqual({ + 'eip155:1': validScopeObject, + }); + }); + + it('returns the scope as is when the scopeString is chain scoped and accounts are defined', () => { + expect(normalizeScope('eip155:1', validScopeObject)).toStrictEqual({ 'eip155:1': validScopeObject, }); }); describe('scopeString is namespace scoped', () => { it('returns the scope as is when `references` is not defined', () => { - expect(flattenScope('eip155', validScopeObject)).toStrictEqual({ + expect(normalizeScope('eip155', validScopeObject)).toStrictEqual({ eip155: validScopeObject, }); }); it('returns one scope per `references` element with `references` excluded from the scopeObject', () => { expect( - flattenScope('eip155', { + normalizeScope('eip155', { ...validScopeObject, references: ['1', '5', '64'], }), @@ -40,16 +52,16 @@ describe('Scope Transform', () => { }); it('returns one deep cloned scope per `references` element', () => { - const flattenedScopes = flattenScope('eip155', { + const noramlizedScopes = normalizeScope('eip155', { ...validScopeObject, references: ['1', '5'], }); - expect(flattenedScopes['eip155:1']).not.toBe( - flattenedScopes['eip155:5'], + expect(noramlizedScopes['eip155:1']).not.toBe( + noramlizedScopes['eip155:5'], ); - expect(flattenedScopes['eip155:1'].methods).not.toBe( - flattenedScopes['eip155:5'].methods, + expect(noramlizedScopes['eip155:1'].methods).not.toBe( + noramlizedScopes['eip155:5'].methods, ); }); }); @@ -200,12 +212,14 @@ describe('Scope Transform', () => { 'eip155:1': { methods: ['a', 'b', 'c'], notifications: ['foo'], + accounts: [], }, }, { 'eip155:1': { methods: ['c', 'd'], notifications: ['bar'], + accounts: [], }, }, ), @@ -213,6 +227,7 @@ describe('Scope Transform', () => { 'eip155:1': { methods: ['a', 'b', 'c', 'd'], notifications: ['foo', 'bar'], + accounts: [], }, }); }); @@ -224,16 +239,19 @@ describe('Scope Transform', () => { 'eip155:1': { methods: ['a', 'b', 'c'], notifications: ['foo'], + accounts: [], }, }, { 'eip155:2': { methods: ['c', 'd'], notifications: ['bar'], + accounts: [], }, 'eip155:3': { methods: [], notifications: [], + accounts: [], }, }, ), @@ -241,23 +259,26 @@ describe('Scope Transform', () => { 'eip155:1': { methods: ['a', 'b', 'c'], notifications: ['foo'], + accounts: [], }, 'eip155:2': { methods: ['c', 'd'], notifications: ['bar'], + accounts: [], }, 'eip155:3': { methods: [], notifications: [], + accounts: [], }, }); }); }); - describe('flattenMergeScopes', () => { - it('flattens scopes and merges any overlapping scopeStrings', () => { + describe('normalizeAndMergeScopes', () => { + it('normalizes scopes and merges any overlapping scopeStrings', () => { expect( - flattenMergeScopes({ + normalizeAndMergeScopes({ eip155: { ...validScopeObject, methods: ['a', 'b'], diff --git a/packages/multichain/src/scope/transform.ts b/packages/multichain/src/scope/transform.ts index 5aeecc6930e..94f69d060d1 100644 --- a/packages/multichain/src/scope/transform.ts +++ b/packages/multichain/src/scope/transform.ts @@ -21,30 +21,36 @@ export const getUniqueArrayItems = (list: Value[]): Value[] => { }; /** - * Flattens a ScopeString and ScopeObject into a separate + * Normalizes a ScopeString and ExternalScopeObject into a separate * ScopeString and ScopeObject for each reference in the `references` - * value if defined. Returns the ScopeString and ScopeObject - * unmodified if it cannot be flattened + * value if defined and adds an empty `accounts` array if not defined. * - * @param scopeString - The string representing the scopeObject - * @param scopeObject - The object that defines the scope + * @param scopeString - The string representing the scope + * @param externalScopeObject - The object that defines the scope * @returns a map of caipChainId to ScopeObjects */ -export const flattenScope = ( +export const normalizeScope = ( scopeString: string, - scopeObject: ExternalScopeObject, + externalScopeObject: ExternalScopeObject, ): ScopesObject => { - const { references, ...restScopeObject } = scopeObject; + const { references, ...scopeObject } = externalScopeObject; const { namespace, reference } = parseScopeString(scopeString); + const normalizedScopeObject = { + accounts: [], + ...scopeObject, + }; + // Scope is already a CAIP-2 ID and has no references to flatten if (!namespace || reference || !references) { - return { [scopeString]: scopeObject }; + return { [scopeString]: normalizedScopeObject }; } const scopeMap: ScopesObject = {}; references.forEach((nestedReference: CaipReference) => { - scopeMap[`${namespace}:${nestedReference}`] = cloneDeep(restScopeObject); + scopeMap[`${namespace}:${nestedReference}`] = cloneDeep( + normalizedScopeObject, + ); }); return scopeMap; }; @@ -62,15 +68,12 @@ export const mergeScopeObject = ( ...scopeObjectA.notifications, ...scopeObjectB.notifications, ]), + accounts: getUniqueArrayItems([ + ...scopeObjectA.accounts, + ...scopeObjectB.accounts, + ]), }; - if (scopeObjectA.accounts || scopeObjectB.accounts) { - mergedScopeObject.accounts = getUniqueArrayItems([ - ...(scopeObjectA.accounts ?? []), - ...(scopeObjectB.accounts ?? []), - ]); - } - if (scopeObjectA.rpcDocuments || scopeObjectB.rpcDocuments) { mergedScopeObject.rpcDocuments = getUniqueArrayItems([ ...(scopeObjectA.rpcDocuments ?? []), @@ -115,14 +118,14 @@ export const mergeScopes = ( return scope; }; -export const flattenMergeScopes = ( +export const normalizeAndMergeScopes = ( scopes: ExternalScopesObject, ): ScopesObject => { - let flattenedScopes: ScopesObject = {}; + let mergedScopes: ScopesObject = {}; Object.keys(scopes).forEach((scopeString) => { - const flattenedScopeMap = flattenScope(scopeString, scopes[scopeString]); - flattenedScopes = mergeScopes(flattenedScopes, flattenedScopeMap); + const normalizedScopes = normalizeScope(scopeString, scopes[scopeString]); + mergedScopes = mergeScopes(mergedScopes, normalizedScopes); }); - return flattenedScopes; + return mergedScopes; }; diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index d9c40b86521..0d5c87fbb13 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -51,8 +51,9 @@ export const KnownNotifications: Record = // These External prefixed types represent the CAIP-217 // Scope and ScopeObject as defined in the spec. export type ExternalScopeString = CaipChainId | CaipNamespace; -export type ExternalScopeObject = ScopeObject & { +export type ExternalScopeObject = Omit & { references?: CaipReference[]; + accounts?: CaipAccountId[]; }; export type ExternalScopesObject = Record< ExternalScopeString, @@ -70,7 +71,7 @@ export type ScopeString = CaipChainId | KnownCaipNamespace.Wallet; export type ScopeObject = { methods: string[]; notifications: string[]; - accounts?: CaipAccountId[]; + accounts: CaipAccountId[]; rpcDocuments?: string[]; rpcEndpoints?: string[]; }; From f30dd8bcf7a0936c970a5e1c1b3920b057e01a8b Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 17 Oct 2024 10:25:29 -0500 Subject: [PATCH 035/146] update @metamask/rpc-errors version --- packages/multichain/package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index e633a1bb2b7..044b203f0ba 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -50,7 +50,7 @@ "@metamask/api-specs": "^0.10.12", "@metamask/controller-utils": "^11.3.0", "@metamask/eth-json-rpc-filters": "^7.0.0", - "@metamask/rpc-errors": "^6.3.1", + "@metamask/rpc-errors": "^7.0.0", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^9.1.0", "@open-rpc/schema-utils-js": "^2.0.5", diff --git a/yarn.lock b/yarn.lock index 5646ea327ad..f2d4d6fc210 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3094,7 +3094,7 @@ __metadata: "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" - "@metamask/rpc-errors": "npm:^6.3.1" + "@metamask/rpc-errors": "npm:^7.0.0" "@metamask/safe-event-emitter": "npm:^3.0.0" "@metamask/utils": "npm:^9.1.0" "@open-rpc/meta-schema": "npm:^1.14.6" From 644f4d0c55cb10ece1a776a80a121ce8506faf95 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 12:35:41 -0700 Subject: [PATCH 036/146] Add isEqualCaseInsensitive to controller-utils --- .../src/TokenDetectionController.ts | 26 ++++--------------- packages/controller-utils/src/index.ts | 1 + packages/controller-utils/src/util.test.ts | 26 +++++++++++++++++++ packages/controller-utils/src/util.ts | 17 ++++++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/packages/assets-controllers/src/TokenDetectionController.ts b/packages/assets-controllers/src/TokenDetectionController.ts index 2459baea38f..76400bc7ccc 100644 --- a/packages/assets-controllers/src/TokenDetectionController.ts +++ b/packages/assets-controllers/src/TokenDetectionController.ts @@ -9,7 +9,11 @@ import type { ControllerStateChangeEvent, } from '@metamask/base-controller'; import contractMap from '@metamask/contract-metadata'; -import { ChainId, safelyExecute } from '@metamask/controller-utils'; +import { + ChainId, + safelyExecute, + isEqualCaseInsensitive, +} from '@metamask/controller-utils'; import type { KeyringControllerGetStateAction, KeyringControllerLockEvent, @@ -44,26 +48,6 @@ import type { const DEFAULT_INTERVAL = 180000; -/** - * Compare 2 given strings and return boolean - * eg: "foo" and "FOO" => true - * eg: "foo" and "bar" => false - * eg: "foo" and 123 => false - * - * @param value1 - first string to compare - * @param value2 - first string to compare - * @returns true if 2 strings are identical when they are lowercase - */ -export function isEqualCaseInsensitive( - value1: string, - value2: string, -): boolean { - if (typeof value1 !== 'string' || typeof value2 !== 'string') { - return false; - } - return value1.toLowerCase() === value2.toLowerCase(); -} - type LegacyToken = { name: string; logo: `${string}.svg`; diff --git a/packages/controller-utils/src/index.ts b/packages/controller-utils/src/index.ts index 265872e6204..3d35d62c0a0 100644 --- a/packages/controller-utils/src/index.ts +++ b/packages/controller-utils/src/index.ts @@ -27,6 +27,7 @@ export { toChecksumHexAddress, toHex, weiHexToGweiDec, + isEqualCaseInsensitive, } from './util'; export * from './types'; export * from './siwe'; diff --git a/packages/controller-utils/src/util.test.ts b/packages/controller-utils/src/util.test.ts index 71dd33e90d6..3126fb7ef12 100644 --- a/packages/controller-utils/src/util.test.ts +++ b/packages/controller-utils/src/util.test.ts @@ -611,3 +611,29 @@ describe('util', () => { }); }); }); + +describe('isEqualCaseInsensitive', () => { + it('returns false for non-string values', () => { + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(null, 'test')).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive('test', null)).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(5, 'test')).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive('test', 5)).toBe(false); + }); + + it('returns false for strings that are not equal', () => { + expect(util.isEqualCaseInsensitive('test', 'test1')).toBe(false); + expect(util.isEqualCaseInsensitive('test1', 'test')).toBe(false); + }); + + it('returns true for strings that are equal', () => { + expect(util.isEqualCaseInsensitive('test', 'TEST')).toBe(true); + expect(util.isEqualCaseInsensitive('test', 'test')).toBe(true); + expect(util.isEqualCaseInsensitive('TEST', 'TEST')).toBe(true); + expect(util.isEqualCaseInsensitive('test', 'Test')).toBe(true); + expect(util.isEqualCaseInsensitive('Test', 'test')).toBe(true); + }); +}); diff --git a/packages/controller-utils/src/util.ts b/packages/controller-utils/src/util.ts index 4d14f71e6f9..4d53b069d9e 100644 --- a/packages/controller-utils/src/util.ts +++ b/packages/controller-utils/src/util.ts @@ -619,3 +619,20 @@ function logOrRethrowError(error: unknown, codesToCatch: number[] = []) { throw error; } } + +/** + * Checks if two strings are equal, ignoring case. + * + * @param value1 - The first string to compare. + * @param value2 - The second string to compare. + * @returns `true` if the strings are equal, ignoring case; otherwise, `false`. + */ +export function isEqualCaseInsensitive( + value1: string, + value2: string, +): boolean { + if (typeof value1 !== 'string' || typeof value2 !== 'string') { + return false; + } + return value1.toLowerCase() === value2.toLowerCase(); +} From 1b78bbc9a4e6f9dd3cab4a2ffded4b013830c2f2 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 12:45:33 -0700 Subject: [PATCH 037/146] create initial multichain package --- README.md | 30 +++++++------ packages/multichain/CHANGELOG.md | 10 +++++ packages/multichain/LICENSE | 20 +++++++++ packages/multichain/README.md | 15 +++++++ packages/multichain/jest.config.js | 26 +++++++++++ packages/multichain/package.json | 60 +++++++++++++++++++++++++ packages/multichain/src/index.test.ts | 9 ++++ packages/multichain/src/index.ts | 9 ++++ packages/multichain/tsconfig.build.json | 10 +++++ packages/multichain/tsconfig.json | 8 ++++ packages/multichain/typedoc.json | 7 +++ tsconfig.build.json | 1 + tsconfig.json | 1 + yarn.lock | 15 +++++++ 14 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 packages/multichain/CHANGELOG.md create mode 100644 packages/multichain/LICENSE create mode 100644 packages/multichain/README.md create mode 100644 packages/multichain/jest.config.js create mode 100644 packages/multichain/package.json create mode 100644 packages/multichain/src/index.test.ts create mode 100644 packages/multichain/src/index.ts create mode 100644 packages/multichain/tsconfig.build.json create mode 100644 packages/multichain/tsconfig.json create mode 100644 packages/multichain/typedoc.json diff --git a/README.md b/README.md index e5961edab24..d13cf342474 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ This repository contains the following packages [^fn1]: - [`@metamask/keyring-controller`](packages/keyring-controller) - [`@metamask/logging-controller`](packages/logging-controller) - [`@metamask/message-manager`](packages/message-manager) +- [`@metamask/multichain`](packages/multichain) - [`@metamask/name-controller`](packages/name-controller) - [`@metamask/network-controller`](packages/network-controller) - [`@metamask/notification-controller`](packages/notification-controller) @@ -71,6 +72,7 @@ linkStyle default opacity:0.5 keyring_controller(["@metamask/keyring-controller"]); logging_controller(["@metamask/logging-controller"]); message_manager(["@metamask/message-manager"]); + multichain(["@metamask/multichain"]); name_controller(["@metamask/name-controller"]); network_controller(["@metamask/network-controller"]); notification_controller(["@metamask/notification-controller"]); @@ -93,14 +95,15 @@ linkStyle default opacity:0.5 address_book_controller --> controller_utils; announcement_controller --> base_controller; approval_controller --> base_controller; - assets_controllers --> accounts_controller; - assets_controllers --> approval_controller; assets_controllers --> base_controller; assets_controllers --> controller_utils; + assets_controllers --> polling_controller; + assets_controllers --> accounts_controller; + assets_controllers --> approval_controller; assets_controllers --> keyring_controller; assets_controllers --> network_controller; - assets_controllers --> polling_controller; assets_controllers --> preferences_controller; + base_controller --> json_rpc_engine; chain_controller --> base_controller; composable_controller --> base_controller; composable_controller --> json_rpc_engine; @@ -110,8 +113,8 @@ linkStyle default opacity:0.5 eth_json_rpc_provider --> json_rpc_engine; gas_fee_controller --> base_controller; gas_fee_controller --> controller_utils; - gas_fee_controller --> network_controller; gas_fee_controller --> polling_controller; + gas_fee_controller --> network_controller; json_rpc_middleware_stream --> json_rpc_engine; keyring_controller --> base_controller; keyring_controller --> message_manager; @@ -124,7 +127,6 @@ linkStyle default opacity:0.5 network_controller --> base_controller; network_controller --> controller_utils; network_controller --> eth_json_rpc_provider; - network_controller --> json_rpc_engine; notification_controller --> base_controller; notification_services_controller --> base_controller; notification_services_controller --> controller_utils; @@ -132,7 +134,6 @@ linkStyle default opacity:0.5 notification_services_controller --> profile_sync_controller; permission_controller --> base_controller; permission_controller --> controller_utils; - permission_controller --> json_rpc_engine; permission_controller --> approval_controller; permission_log_controller --> base_controller; permission_log_controller --> json_rpc_engine; @@ -145,9 +146,11 @@ linkStyle default opacity:0.5 preferences_controller --> controller_utils; preferences_controller --> keyring_controller; profile_sync_controller --> base_controller; + profile_sync_controller --> keyring_controller; + profile_sync_controller --> accounts_controller; + profile_sync_controller --> network_controller; queued_request_controller --> base_controller; queued_request_controller --> controller_utils; - queued_request_controller --> json_rpc_engine; queued_request_controller --> network_controller; queued_request_controller --> selected_network_controller; rate_limit_controller --> base_controller; @@ -155,26 +158,25 @@ linkStyle default opacity:0.5 selected_network_controller --> json_rpc_engine; selected_network_controller --> network_controller; selected_network_controller --> permission_controller; - signature_controller --> approval_controller; signature_controller --> base_controller; signature_controller --> controller_utils; + signature_controller --> approval_controller; signature_controller --> keyring_controller; signature_controller --> logging_controller; - signature_controller --> message_manager; - transaction_controller --> accounts_controller; - transaction_controller --> approval_controller; transaction_controller --> base_controller; transaction_controller --> controller_utils; + transaction_controller --> accounts_controller; + transaction_controller --> approval_controller; + transaction_controller --> eth_json_rpc_provider; transaction_controller --> gas_fee_controller; transaction_controller --> network_controller; - transaction_controller --> eth_json_rpc_provider; - user_operation_controller --> approval_controller; user_operation_controller --> base_controller; user_operation_controller --> controller_utils; + user_operation_controller --> polling_controller; + user_operation_controller --> approval_controller; user_operation_controller --> gas_fee_controller; user_operation_controller --> keyring_controller; user_operation_controller --> network_controller; - user_operation_controller --> polling_controller; user_operation_controller --> transaction_controller; ``` diff --git a/packages/multichain/CHANGELOG.md b/packages/multichain/CHANGELOG.md new file mode 100644 index 00000000000..b518709c7b8 --- /dev/null +++ b/packages/multichain/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +[Unreleased]: https://github.com/MetaMask/core/ diff --git a/packages/multichain/LICENSE b/packages/multichain/LICENSE new file mode 100644 index 00000000000..6f8bff03fc4 --- /dev/null +++ b/packages/multichain/LICENSE @@ -0,0 +1,20 @@ +MIT License + +Copyright (c) 2024 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE diff --git a/packages/multichain/README.md b/packages/multichain/README.md new file mode 100644 index 00000000000..dc89e0fade9 --- /dev/null +++ b/packages/multichain/README.md @@ -0,0 +1,15 @@ +# `@metamask/multichain` + +Provides types, helpers, adapters, and wrappers for facilitating CAIP Multichain sessions + +## Installation + +`yarn add @metamask/multichain` + +or + +`npm install @metamask/multichain` + +## Contributing + +This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme). diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js new file mode 100644 index 00000000000..ca084133399 --- /dev/null +++ b/packages/multichain/jest.config.js @@ -0,0 +1,26 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +const merge = require('deepmerge'); +const path = require('path'); + +const baseConfig = require('../../jest.config.packages'); + +const displayName = path.basename(__dirname); + +module.exports = merge(baseConfig, { + // The display name when running multiple projects + displayName, + + // An object that configures minimum threshold enforcement for coverage results + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}); diff --git a/packages/multichain/package.json b/packages/multichain/package.json new file mode 100644 index 00000000000..8bb21596986 --- /dev/null +++ b/packages/multichain/package.json @@ -0,0 +1,60 @@ +{ + "name": "@metamask/multichain", + "version": "0.0.0", + "description": "Provides types, helpers, adapters, and wrappers for facilitating CAIP Multichain sessions", + "keywords": [ + "MetaMask", + "Ethereum" + ], + "homepage": "https://github.com/MetaMask/core/tree/main/packages/multichain#readme", + "bugs": { + "url": "https://github.com/MetaMask/core/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/core.git" + }, + "license": "MIT", + "sideEffects": false, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js", + "types": "./dist/types/index.d.ts" + }, + "./package.json": "./package.json" + }, + "main": "./dist/index.js", + "types": "./dist/types/index.d.ts", + "files": [ + "dist/" + ], + "scripts": { + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build:docs": "typedoc", + "changelog:update": "../../scripts/update-changelog.sh @metamask/multichain", + "changelog:validate": "../../scripts/validate-changelog.sh @metamask/multichain", + "publish:preview": "yarn npm publish --tag preview", + "test": "jest --reporters=jest-silent-reporter", + "test:clean": "jest --clearCache", + "test:verbose": "jest --verbose", + "test:watch": "jest --watch" + }, + "devDependencies": { + "@metamask/auto-changelog": "^3.4.4", + "@types/jest": "^27.4.1", + "deepmerge": "^4.2.2", + "jest": "^27.5.1", + "ts-jest": "^27.1.4", + "typedoc": "^0.24.8", + "typedoc-plugin-missing-exports": "^2.0.0", + "typescript": "~5.2.2" + }, + "engines": { + "node": "^18.18 || >=20" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts new file mode 100644 index 00000000000..bc062d3694a --- /dev/null +++ b/packages/multichain/src/index.test.ts @@ -0,0 +1,9 @@ +import greeter from '.'; + +describe('Test', () => { + it('greets', () => { + const name = 'Huey'; + const result = greeter(name); + expect(result).toBe('Hello, Huey!'); + }); +}); diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts new file mode 100644 index 00000000000..6972c117292 --- /dev/null +++ b/packages/multichain/src/index.ts @@ -0,0 +1,9 @@ +/** + * Example function that returns a greeting for the given name. + * + * @param name - The name to greet. + * @returns The greeting. + */ +export default function greeter(name: string): string { + return `Hello, ${name}!`; +} diff --git a/packages/multichain/tsconfig.build.json b/packages/multichain/tsconfig.build.json new file mode 100644 index 00000000000..02a0eea03fe --- /dev/null +++ b/packages/multichain/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.packages.build.json", + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist", + "rootDir": "./src" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/multichain/tsconfig.json b/packages/multichain/tsconfig.json new file mode 100644 index 00000000000..025ba2ef7f4 --- /dev/null +++ b/packages/multichain/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "baseUrl": "./" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/multichain/typedoc.json b/packages/multichain/typedoc.json new file mode 100644 index 00000000000..c9da015dbf8 --- /dev/null +++ b/packages/multichain/typedoc.json @@ -0,0 +1,7 @@ +{ + "entryPoints": ["./src/index.ts"], + "excludePrivate": true, + "hideGenerator": true, + "out": "docs", + "tsconfig": "./tsconfig.build.json" +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 4e485ea1896..6102878c563 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -18,6 +18,7 @@ { "path": "./packages/keyring-controller/tsconfig.build.json" }, { "path": "./packages/logging-controller/tsconfig.build.json" }, { "path": "./packages/message-manager/tsconfig.build.json" }, + { "path": "./packages/multichain/tsconfig.build.json" }, { "path": "./packages/name-controller/tsconfig.build.json" }, { "path": "./packages/network-controller/tsconfig.build.json" }, { "path": "./packages/notification-controller/tsconfig.build.json" }, diff --git a/tsconfig.json b/tsconfig.json index f886671a63c..127a643b9d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ { "path": "./packages/json-rpc-middleware-stream" }, { "path": "./packages/keyring-controller" }, { "path": "./packages/message-manager" }, + { "path": "./packages/multichain" }, { "path": "./packages/name-controller" }, { "path": "./packages/network-controller" }, { "path": "./packages/notification-controller" }, diff --git a/yarn.lock b/yarn.lock index ed66bdca2d3..10990344a06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3021,6 +3021,21 @@ __metadata: languageName: node linkType: hard +"@metamask/multichain@workspace:packages/multichain": + version: 0.0.0-use.local + resolution: "@metamask/multichain@workspace:packages/multichain" + dependencies: + "@metamask/auto-changelog": "npm:^3.4.4" + "@types/jest": "npm:^27.4.1" + deepmerge: "npm:^4.2.2" + jest: "npm:^27.5.1" + ts-jest: "npm:^27.1.4" + typedoc: "npm:^0.24.8" + typedoc-plugin-missing-exports: "npm:^2.0.0" + typescript: "npm:~5.2.2" + languageName: unknown + linkType: soft + "@metamask/name-controller@workspace:packages/name-controller": version: 0.0.0-use.local resolution: "@metamask/name-controller@workspace:packages/name-controller" From fc28c89c17de6e9593c6551cd159ebd10587489c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:07:43 -0700 Subject: [PATCH 038/146] remove API related logic --- .../src/handlers/wallet-getSession.test.ts | 117 -------- .../src/handlers/wallet-getSession.ts | 66 ---- .../src/handlers/wallet-invokeMethod.test.ts | 282 ------------------ .../src/handlers/wallet-invokeMethod.ts | 120 -------- .../src/handlers/wallet-revokeSession.test.ts | 92 ------ .../src/handlers/wallet-revokeSession.ts | 54 ---- packages/multichain/src/index.test.ts | 11 - packages/multichain/src/index.ts | 11 - .../MultichainMiddlewareManager.test.ts | 171 ----------- .../MultichainMiddlewareManager.ts | 137 --------- .../MultichainSubscriptionManager.test.ts | 120 -------- .../MultichainSubscriptionManager.ts | 160 ---------- .../multichainMethodCallValidator.ts | 101 ------- .../src/scope/authorization.test.ts | 133 +-------- .../multichain/src/scope/authorization.ts | 32 -- packages/multichain/src/scope/filter.test.ts | 168 ----------- packages/multichain/src/scope/filter.ts | 44 --- 17 files changed, 1 insertion(+), 1818 deletions(-) delete mode 100644 packages/multichain/src/handlers/wallet-getSession.test.ts delete mode 100644 packages/multichain/src/handlers/wallet-getSession.ts delete mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.test.ts delete mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.ts delete mode 100644 packages/multichain/src/handlers/wallet-revokeSession.test.ts delete mode 100644 packages/multichain/src/handlers/wallet-revokeSession.ts delete mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts delete mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.ts delete mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts delete mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.ts delete mode 100644 packages/multichain/src/middlewares/multichainMethodCallValidator.ts delete mode 100644 packages/multichain/src/scope/filter.test.ts delete mode 100644 packages/multichain/src/scope/filter.ts diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts deleted file mode 100644 index ca74cc9b909..00000000000 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import type { JsonRpcRequest } from '@metamask/utils'; - -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { walletGetSession } from './wallet-getSession'; - -const baseRequest: JsonRpcRequest & { origin: string } = { - origin: 'http://test.com', - jsonrpc: '2.0' as const, - method: 'wallet_getSession', - params: {}, - id: 1, -}; - -const createMockedHandler = () => { - const next = jest.fn(); - const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ - value: { - requiredScopes: { - 'eip155:1': { - methods: ['eth_call'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], - accounts: [], - }, - }, - optionalScopes: { - 'eip155:1': { - methods: ['net_version'], - notifications: ['chainChanged'], - accounts: [], - }, - wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - }, - }, - }); - const response = { - result: { - sessionScopes: {}, - }, - id: 1, - jsonrpc: '2.0' as const, - }; - const handler = (request: JsonRpcRequest & { origin: string }) => - walletGetSession.implementation(request, response, next, end, { - getCaveat, - }); - - return { - next, - response, - end, - getCaveat, - handler, - }; -}; - -describe('wallet_getSession', () => { - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const { handler, getCaveat } = createMockedHandler(); - - await handler(baseRequest); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - }); - - it('returns empty scopes if the CAIP-25 endowment permission does not exist', async () => { - const { handler, response, getCaveat } = createMockedHandler(); - getCaveat.mockImplementation(() => { - throw new Error('permission not found'); - }); - - await handler(baseRequest); - expect(response.result).toStrictEqual({ - sessionScopes: {}, - }); - }); - - it('returns the merged scopes', async () => { - const { handler, response } = createMockedHandler(); - - await handler(baseRequest); - expect(response.result).toStrictEqual({ - sessionScopes: { - 'eip155:1': { - methods: ['eth_call', 'net_version'], - notifications: ['chainChanged'], - accounts: [], - }, - 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], - accounts: [], - }, - wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - }, - }); - }); -}); diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts deleted file mode 100644 index ad3e4e5569b..00000000000 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { Caveat } from '@metamask/permission-controller'; -import type { JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils'; - -import type { Caip25CaveatValue } from '../caip25Permission'; -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import type { ScopesObject } from '../scope/types'; - -/** - * Handler for the `wallet_getSession` RPC method. - * - * @param request - The request object. - * @param response - The response object. - * @param _next - The next middleware function. - * @param end - The end function. - * @param hooks - The hooks object. - * @param hooks.getCaveat - Function to retrieve a caveat. - */ -async function walletGetSessionHandler( - request: JsonRpcRequest & { origin: string }, - response: JsonRpcSuccess<{ sessionScopes: ScopesObject }>, - _next: () => void, - end: () => void, - hooks: { - getCaveat: ( - origin: string, - endowmentPermissionName: string, - caveatType: string, - ) => Caveat; - }, -) { - let caveat; - try { - caveat = hooks.getCaveat( - request.origin, - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - } catch (e) { - // noop - } - - if (!caveat) { - response.result = { sessionScopes: {} }; - return end(); - } - - response.result = { - sessionScopes: mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - ), - }; - return end(); -} - -export const walletGetSession = { - methodNames: ['wallet_getSession'], - implementation: walletGetSessionHandler, - hookNames: { - getCaveat: true, - }, -}; diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts deleted file mode 100644 index 208bccc3371..00000000000 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ /dev/null @@ -1,282 +0,0 @@ -import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; - -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { walletInvokeMethod } from './wallet-invokeMethod'; - -const createMockedRequest = () => ({ - jsonrpc: '2.0' as const, - id: 0, - origin: 'http://test.com', - method: 'wallet_invokeMethod', - params: { - scope: 'eip155:1', - request: { - method: 'eth_call', - params: { - foo: 'bar', - }, - }, - }, -}); - -const createMockedHandler = () => { - const next = jest.fn(); - const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ - value: { - requiredScopes: { - 'eip155:1': { - methods: ['eth_call'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], - accounts: [], - }, - }, - optionalScopes: { - 'eip155:1': { - methods: ['net_version'], - notifications: [], - accounts: [], - }, - wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - unhandled: { - methods: ['foobar'], - notifications: [], - accounts: [], - }, - }, - isMultichainOrigin: true, - }, - }); - const findNetworkClientIdByChainId = jest.fn().mockReturnValue('mainnet'); - const getSelectedNetworkClientId = jest - .fn() - .mockReturnValue('selectedNetworkClientId'); - const handler = (request: JsonRpcRequest & { origin: string }) => - walletInvokeMethod.implementation( - request, - { jsonrpc: '2.0', id: 1 }, - next, - end, - { - getCaveat, - findNetworkClientIdByChainId, - getSelectedNetworkClientId, - }, - ); - - return { - next, - end, - getCaveat, - findNetworkClientIdByChainId, - getSelectedNetworkClientId, - handler, - }; -}; - -describe('wallet_invokeMethod', () => { - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const request = createMockedRequest(); - const { handler, getCaveat } = createMockedHandler(); - await handler(request); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - }); - - it('throws an unauthorized error when there is no CAIP-25 endowment permission', async () => { - const request = createMockedRequest(); - const { handler, getCaveat, end } = createMockedHandler(); - getCaveat.mockImplementation(() => { - throw new Error('permission not found'); - }); - await handler(request); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('throws an unauthorized error when the CAIP-25 endowment permission was not granted from the multichain flow', async () => { - const request = createMockedRequest(); - const { handler, getCaveat, end } = createMockedHandler(); - getCaveat.mockReturnValue({ - value: { - isMultichainOrigin: false, - }, - }); - await handler(request); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('throws an unauthorized error if the requested scope is not authorized', async () => { - const request = createMockedRequest(); - const { handler, end } = createMockedHandler(); - - await handler({ - ...request, - params: { - ...request.params, - scope: 'eip155:999', - }, - }); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('throws an unauthorized error if the requested scope method is not authorized', async () => { - const request = createMockedRequest(); - const { handler, end } = createMockedHandler(); - - await handler({ - ...request, - params: { - ...request.params, - request: { - ...request.params.request, - method: 'unauthorized_method', - }, - }, - }); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('throws an internal error for authorized but unhandled scopes', async () => { - const request = createMockedRequest(); - const { handler, end } = createMockedHandler(); - - await handler({ - ...request, - params: { - ...request.params, - scope: 'unhandled', - request: { - ...request.params.request, - method: 'foobar', - }, - }, - }); - - expect(end).toHaveBeenCalledWith(rpcErrors.internal()); - }); - - describe('ethereum scope', () => { - it('gets the networkClientId for the chainId', async () => { - const request = createMockedRequest(); - const { handler, findNetworkClientIdByChainId } = createMockedHandler(); - - await handler(request); - expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); - }); - - it('throws an internal error if a networkClientId does not exist for the chainId', async () => { - const request = createMockedRequest(); - const { handler, findNetworkClientIdByChainId, end } = - createMockedHandler(); - findNetworkClientIdByChainId.mockReturnValue(undefined); - - await handler(request); - expect(end).toHaveBeenCalledWith(rpcErrors.internal()); - }); - - it('sets the networkClientId and unwraps the CAIP-27 request', async () => { - const request = createMockedRequest(); - const { handler, next } = createMockedHandler(); - - await handler(request); - expect(request).toStrictEqual({ - jsonrpc: '2.0' as const, - id: 0, - scope: 'eip155:1', - origin: 'http://test.com', - networkClientId: 'mainnet', - method: 'eth_call', - params: { - foo: 'bar', - }, - }); - expect(next).toHaveBeenCalled(); - }); - }); - - describe('wallet scope', () => { - it('gets the networkClientId for the globally selected network', async () => { - const request = createMockedRequest(); - const { handler, getSelectedNetworkClientId } = createMockedHandler(); - - await handler({ - ...request, - params: { - ...request.params, - scope: 'wallet', - request: { - ...request.params.request, - method: 'wallet_watchAsset', - }, - }, - }); - expect(getSelectedNetworkClientId).toHaveBeenCalled(); - }); - - it('throws an internal error if a networkClientId cannot be retrieved for the globally selected network', async () => { - const request = createMockedRequest(); - const { handler, getSelectedNetworkClientId, end } = - createMockedHandler(); - getSelectedNetworkClientId.mockReturnValue(undefined); - - await handler({ - ...request, - params: { - ...request.params, - scope: 'wallet', - request: { - ...request.params.request, - method: 'wallet_watchAsset', - }, - }, - }); - expect(end).toHaveBeenCalledWith(rpcErrors.internal()); - }); - - it('sets the networkClientId and unwraps the CAIP-27 request', async () => { - const request = createMockedRequest(); - const { handler, next } = createMockedHandler(); - - const walletRequest = { - ...request, - params: { - ...request.params, - scope: 'wallet', - request: { - ...request.params.request, - method: 'wallet_watchAsset', - }, - }, - }; - await handler(walletRequest); - expect(walletRequest).toStrictEqual({ - jsonrpc: '2.0' as const, - id: 0, - scope: 'wallet', - origin: 'http://test.com', - networkClientId: 'selectedNetworkClientId', - method: 'wallet_watchAsset', - params: { - foo: 'bar', - }, - }); - expect(next).toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts deleted file mode 100644 index 3df3ca8346f..00000000000 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { Caveat } from '@metamask/permission-controller'; -import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; -import type { - Json, - JsonRpcRequest, - PendingJsonRpcResponse, -} from '@metamask/utils'; -import { numberToHex } from '@metamask/utils'; - -import type { Caip25CaveatValue } from '../caip25Permission'; -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import type { ScopeString } from '../scope/types'; -import { parseScopeString } from '../scope/types'; - -/** - * Handler for the `wallet_invokeMethod` RPC method. - * - * @param request - The request object. - * @param _response - The response object. - * @param next - The next middleware function. - * @param end - The end function. - * @param hooks - The hooks object. - * @param hooks.getCaveat - the hook for getting a caveat from a permission for an origin. - * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId. - * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. - */ -async function walletInvokeMethodHandler( - request: JsonRpcRequest & { origin: string }, - _response: PendingJsonRpcResponse, - next: () => void, - end: (error: Error) => void, - hooks: { - getCaveat: ( - origin: string, - endowmentPermissionName: string, - caveatType: string, - ) => Caveat; - findNetworkClientIdByChainId: (chainId: string) => string | undefined; - getSelectedNetworkClientId: () => string; - }, -) { - const { scope, request: wrappedRequest } = request.params as { - scope: ScopeString; - request: JsonRpcRequest; - }; - - let caveat; - try { - caveat = hooks.getCaveat( - request.origin, - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - } catch (e) { - // noop - } - if (!caveat?.value?.isMultichainOrigin) { - return end(providerErrors.unauthorized()); - } - - const scopeObject = mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - )[scope]; - - if (!scopeObject?.methods?.includes(wrappedRequest.method)) { - return end(providerErrors.unauthorized()); - } - - const { namespace, reference } = parseScopeString(scope); - - let networkClientId; - switch (namespace) { - case 'wallet': - networkClientId = hooks.getSelectedNetworkClientId(); - break; - case 'eip155': - if (reference) { - networkClientId = hooks.findNetworkClientIdByChainId( - numberToHex(parseInt(reference, 10)), - ); - } - break; - default: - console.error( - 'failed to resolve namespace for wallet_invokeMethod', - request, - ); - return end(rpcErrors.internal()); - } - - if (!networkClientId) { - console.error( - 'failed to resolve network client for wallet_invokeMethod', - request, - ); - return end(rpcErrors.internal()); - } - - Object.assign(request, { - scope, - networkClientId, - method: wrappedRequest.method, - params: wrappedRequest.params, - }); - return next(); -} -export const walletInvokeMethod = { - methodNames: ['wallet_invokeMethod'], - implementation: walletInvokeMethodHandler, - hookNames: { - getCaveat: true, - findNetworkClientIdByChainId: true, - getSelectedNetworkClientId: true, - }, -}; diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.ts b/packages/multichain/src/handlers/wallet-revokeSession.test.ts deleted file mode 100644 index e11b89f42c2..00000000000 --- a/packages/multichain/src/handlers/wallet-revokeSession.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { - PermissionDoesNotExistError, - UnrecognizedSubjectError, -} from '@metamask/permission-controller'; -import { rpcErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; - -import { Caip25EndowmentPermissionName } from '../caip25Permission'; -import { walletRevokeSession } from './wallet-revokeSession'; - -const baseRequest: JsonRpcRequest & { origin: string } = { - origin: 'http://test.com', - params: {}, - jsonrpc: '2.0' as const, - id: 1, - method: 'wallet_revokeSession', -}; - -const createMockedHandler = () => { - const next = jest.fn(); - const end = jest.fn(); - const revokePermission = jest.fn(); - const response = { - result: true, - id: 1, - jsonrpc: '2.0' as const, - }; - const handler = (request: JsonRpcRequest & { origin: string }) => - walletRevokeSession.implementation(request, response, next, end, { - revokePermission, - }); - - return { - next, - response, - end, - revokePermission, - handler, - }; -}; - -describe('wallet_revokeSession', () => { - it('revokes the the CAIP-25 endowment permission', async () => { - const { handler, revokePermission } = createMockedHandler(); - - await handler(baseRequest); - expect(revokePermission).toHaveBeenCalledWith( - 'http://test.com', - Caip25EndowmentPermissionName, - ); - }); - - it('returns true if the CAIP-25 endowment permission does not exist', async () => { - const { handler, response, revokePermission } = createMockedHandler(); - revokePermission.mockImplementation(() => { - throw new PermissionDoesNotExistError( - 'foo.com', - Caip25EndowmentPermissionName, - ); - }); - - await handler(baseRequest); - expect(response.result).toBe(true); - }); - - it('returns true if the subject does not exist', async () => { - const { handler, response, revokePermission } = createMockedHandler(); - revokePermission.mockImplementation(() => { - throw new UnrecognizedSubjectError('foo.com'); - }); - - await handler(baseRequest); - expect(response.result).toBe(true); - }); - - it('throws an internal RPC error if something unexpected goes wrong with revoking the permission', async () => { - const { handler, revokePermission, end } = createMockedHandler(); - revokePermission.mockImplementation(() => { - throw new Error('revoke failed'); - }); - - await handler(baseRequest); - expect(end).toHaveBeenCalledWith(rpcErrors.internal()); - }); - - it('returns true if the permission was revoked', async () => { - const { handler, response } = createMockedHandler(); - - await handler(baseRequest); - expect(response.result).toBe(true); - }); -}); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts deleted file mode 100644 index 51e31073f0d..00000000000 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { - JsonRpcEngineNextCallback, - JsonRpcEngineEndCallback, -} from '@metamask/json-rpc-engine'; -import { - PermissionDoesNotExistError, - UnrecognizedSubjectError, -} from '@metamask/permission-controller'; -import { rpcErrors } from '@metamask/rpc-errors'; -import type { JsonRpcSuccess, Json, JsonRpcRequest } from '@metamask/utils'; - -import { Caip25EndowmentPermissionName } from '../caip25Permission'; - -/** - * Handles the `wallet_revokeSession` RPC method. - * - * @param request - The JSON-RPC request object. - * @param response - The JSON-RPC response object. - * @param _next - The next middleware function. - * @param end - The end callback function. - * @param hooks - The hooks object. - * @param hooks.revokePermission - The revokePermission function. - */ -async function walletRevokeSessionHandler( - request: JsonRpcRequest & { origin: string }, - response: JsonRpcSuccess, - _next: JsonRpcEngineNextCallback, - end: JsonRpcEngineEndCallback, - hooks: { - revokePermission: (origin: string, permissionName: string) => void; - }, -) { - try { - hooks.revokePermission(request.origin, Caip25EndowmentPermissionName); - } catch (err) { - if ( - !(err instanceof UnrecognizedSubjectError) && - !(err instanceof PermissionDoesNotExistError) - ) { - console.error(err); - return end(rpcErrors.internal()); - } - } - - response.result = true; - return end(); -} -export const walletRevokeSession = { - methodNames: ['wallet_revokeSession'], - implementation: walletRevokeSessionHandler, - hookNames: { - revokePermission: true, - }, -}; diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index d06cd6094eb..7cf4f393210 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -10,18 +10,7 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", - "walletGetSession", - "walletInvokeMethod", - "walletRevokeSession", - "multichainMethodCallValidatorMiddleware", - "MultichainMiddlewareManager", - "MultichainSubscriptionManager", - "assertScopeSupported", - "assertScopesSupported", "validateAndNormalizeScopes", - "bucketScopes", - "bucketScopesBySupport", - "filterScopesSupported", "isSupportedScopeString", "isSupportedAccount", "isSupportedMethod", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index f764ea5b3ec..5c10c8f8fab 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -9,21 +9,10 @@ export { setPermittedEthChainIds, } from './adapters/caip-permission-adapter-permittedChains'; -export { walletGetSession } from './handlers/wallet-getSession'; -export { walletInvokeMethod } from './handlers/wallet-invokeMethod'; -export { walletRevokeSession } from './handlers/wallet-revokeSession'; - -export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator'; -export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager'; -export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager'; - -export { assertScopeSupported, assertScopesSupported } from './scope/assert'; export type { Caip25Authorization } from './scope/authorization'; export { validateAndNormalizeScopes, - bucketScopes, } from './scope/authorization'; -export { bucketScopesBySupport, filterScopesSupported } from './scope/filter'; export * from './scope/types'; export { isSupportedScopeString, diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts deleted file mode 100644 index 4a358896fce..00000000000 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ /dev/null @@ -1,171 +0,0 @@ -import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; -import { MultichainMiddlewareManager } from './MultichainMiddlewareManager'; - -const scope = 'eip155:1'; -const origin = 'example.com'; -const tabId = 123; - -describe('MultichainMiddlewareManager', () => { - it('should add middleware and get called for the scope, origin, and tabId', () => { - const multichainMiddlewareManager = new MultichainMiddlewareManager(); - const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - multichainMiddlewareManager.addMiddleware({ - scope, - origin, - tabId, - middleware: middlewareSpy, - }); - - const middleware = - multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( - origin, - 123, - ); - - const nextSpy = jest.fn(); - const endSpy = jest.fn(); - - middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(middlewareSpy).toHaveBeenCalledWith( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(nextSpy).not.toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); - }); - - it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', async () => { - const multichainMiddlewareManager = new MultichainMiddlewareManager(); - const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - multichainMiddlewareManager.addMiddleware({ - scope, - origin, - tabId, - middleware: middlewareSpy, - }); - - const middleware = - multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( - origin, - 123, - ); - - await middleware.destroy?.(); - - const nextSpy = jest.fn(); - const endSpy = jest.fn(); - - middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); - }); - - it('should remove middleware by scope', () => { - const multichainMiddlewareManager = new MultichainMiddlewareManager(); - const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - multichainMiddlewareManager.addMiddleware({ - scope, - origin, - tabId, - middleware: middlewareSpy, - }); - - multichainMiddlewareManager.removeMiddlewareByScope(scope); - - const middleware = - multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( - origin, - 123, - ); - - const nextSpy = jest.fn(); - const endSpy = jest.fn(); - - middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); - }); - - it('should remove middleware by scope and origin', () => { - const multichainMiddlewareManager = new MultichainMiddlewareManager(); - const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - multichainMiddlewareManager.addMiddleware({ - scope, - origin, - tabId, - middleware: middlewareSpy, - }); - - multichainMiddlewareManager.removeMiddlewareByScopeAndOrigin(scope, origin); - - const middleware = - multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( - origin, - 123, - ); - - const nextSpy = jest.fn(); - const endSpy = jest.fn(); - - middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); - }); - - it('should remove middleware by origin and tabId', () => { - const multichainMiddlewareManager = new MultichainMiddlewareManager(); - const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - multichainMiddlewareManager.addMiddleware({ - scope, - origin, - tabId, - middleware: middlewareSpy, - }); - - multichainMiddlewareManager.removeMiddlewareByOriginAndTabId(origin, tabId); - - const middleware = - multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( - origin, - 123, - ); - - const nextSpy = jest.fn(); - const endSpy = jest.fn(); - - middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, - { jsonrpc: '2.0', id: 0 }, - nextSpy, - endSpy, - ); - expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts deleted file mode 100644 index d1e52f93852..00000000000 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ /dev/null @@ -1,137 +0,0 @@ -import type { - JsonRpcEngineEndCallback, - JsonRpcEngineNextCallback, -} from '@metamask/json-rpc-engine'; -import type { - Json, - JsonRpcRequest, - PendingJsonRpcResponse, -} from '@metamask/utils'; - -import type { ExternalScopeString } from '../scope/types'; - -export type ExtendedJsonRpcMiddleware = { - ( - req: JsonRpcRequest & { scope: string }, - res: PendingJsonRpcResponse, - next: JsonRpcEngineNextCallback, - end: JsonRpcEngineEndCallback, - ): void; - destroy?: () => void | Promise; -}; - -type MiddlewareKey = { - scope: ExternalScopeString; - origin: string; - tabId?: number; -}; -type MiddlewareEntry = MiddlewareKey & { - middleware: ExtendedJsonRpcMiddleware; -}; - -export class MultichainMiddlewareManager { - #middlewares: MiddlewareEntry[] = []; - - #getMiddlewareEntry({ - scope, - origin, - tabId, - }: MiddlewareKey): MiddlewareEntry | undefined { - return this.#middlewares.find((middlewareEntry) => { - return ( - middlewareEntry.scope === scope && - middlewareEntry.origin === origin && - middlewareEntry.tabId === tabId - ); - }); - } - - #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareKey) { - this.#middlewares = this.#middlewares.filter((middlewareEntry) => { - return ( - middlewareEntry.scope !== scope || - middlewareEntry.origin !== origin || - middlewareEntry.tabId !== tabId - ); - }); - } - - addMiddleware(middlewareEntry: MiddlewareEntry) { - const { scope, origin, tabId } = middlewareEntry; - if (!this.#getMiddlewareEntry({ scope, origin, tabId })) { - this.#middlewares.push(middlewareEntry); - } - } - - #removeMiddleware(middlewareKey: MiddlewareKey) { - const existingMiddlewareEntry = this.#getMiddlewareEntry(middlewareKey); - if (!existingMiddlewareEntry) { - return; - } - - // When the destroy function on the middleware is async, - // we don't need to wait for it complete - // eslint-disable-next-line no-void - void existingMiddlewareEntry.middleware.destroy?.(); - - this.#removeMiddlewareEntry(middlewareKey); - } - - removeMiddlewareByScope(scope: ExternalScopeString) { - this.#middlewares.forEach((middlewareEntry) => { - if (middlewareEntry.scope === scope) { - this.#removeMiddleware(middlewareEntry); - } - }); - } - - removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) { - this.#middlewares.forEach((middlewareEntry) => { - if ( - middlewareEntry.scope === scope && - middlewareEntry.origin === origin - ) { - this.#removeMiddleware(middlewareEntry); - } - }); - } - - removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) { - this.#middlewares.forEach((middlewareEntry) => { - if ( - middlewareEntry.origin === origin && - middlewareEntry.tabId === tabId - ) { - this.#removeMiddleware(middlewareEntry); - } - }); - } - - generateMultichainMiddlewareForOriginAndTabId( - origin: string, - tabId?: number, - ) { - const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => { - const { scope } = req; - const middlewareEntry = this.#getMiddlewareEntry({ - scope, - origin, - tabId, - }); - - if (middlewareEntry) { - middlewareEntry.middleware(req, res, next, end); - } else { - return next(); - } - return undefined; - }; - middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind( - this, - origin, - tabId, - ); - - return middleware; - } -} diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts deleted file mode 100644 index cf05aa5c5a9..00000000000 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; - -import { MultichainSubscriptionManager } from './MultichainSubscriptionManager'; - -jest.mock('@metamask/eth-json-rpc-filters/subscriptionManager', () => - jest.fn(), -); -const MockCreateSubscriptionManager = jest.mocked(createSubscriptionManager); - -const newHeadsNotificationMock = { - method: 'eth_subscription', - params: { - result: { - difficulty: '0x15d9223a23aa', - extraData: '0xd983010305844765746887676f312e342e328777696e646f7773', - gasLimit: '0x47e7c4', - gasUsed: '0x38658', - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - miner: '0xf8b483dba2c3b7176a3da549ad41a48bb3121069', - nonce: '0x084149998194cc5f', - number: '0x1348c9', - parentHash: - '0x7736fab79e05dc611604d22470dadad26f56fe494421b5b333de816ce1f25701', - receiptRoot: - '0x2fab35823ad00c7bb388595cb46652fe7886e00660a01e867824d3dceb1c8d36', - sha3Uncles: - '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - stateRoot: - '0xb3346685172db67de536d8765c43c31009d0eb3bd9c501c9be3229203f15f378', - timestamp: '0x56ffeff8', - }, - }, -}; - -const scope = 'eip155:1'; -const origin = 'example.com'; -const tabId = 123; - -const createMultichainSubscriptionManager = () => { - const mockFindNetworkClientIdByChainId = jest.fn(); - const mockGetNetworkClientById = jest.fn().mockImplementation(() => ({ - blockTracker: {}, - provider: {}, - })); - const multichainSubscriptionManager = new MultichainSubscriptionManager({ - findNetworkClientIdByChainId: mockFindNetworkClientIdByChainId, - getNetworkClientById: mockGetNetworkClientById, - }); - - return { multichainSubscriptionManager }; -}; - -describe('MultichainSubscriptionManager', () => { - const mockSubscriptionManager = { - events: { - on: jest.fn(), - }, - destroy: jest.fn(), - }; - - beforeEach(() => { - MockCreateSubscriptionManager.mockReturnValue(mockSubscriptionManager); - }); - - it('should subscribe to a scope, origin, and tabId', () => { - const { multichainSubscriptionManager } = - createMultichainSubscriptionManager(); - multichainSubscriptionManager.subscribe({ scope, origin, tabId }); - const onNotificationSpy = jest.fn(); - multichainSubscriptionManager.on('notification', onNotificationSpy); - - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); - - expect(onNotificationSpy).toHaveBeenCalledWith(origin, tabId, { - method: 'wallet_notify', - params: { - scope, - notification: newHeadsNotificationMock, - }, - }); - }); - - it('should unsubscribe from a scope', () => { - const { multichainSubscriptionManager } = - createMultichainSubscriptionManager(); - multichainSubscriptionManager.subscribe({ scope, origin, tabId }); - multichainSubscriptionManager.unsubscribeByScope(scope); - - expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); - }); - - it('should unsubscribe from a scope and origin', () => { - const { multichainSubscriptionManager } = - createMultichainSubscriptionManager(); - multichainSubscriptionManager.subscribe({ scope, origin, tabId }); - multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); - - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); - - expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); - }); - - it('should unsubscribe from a origin and tabId', () => { - const { multichainSubscriptionManager } = - createMultichainSubscriptionManager(); - multichainSubscriptionManager.subscribe({ scope, origin, tabId }); - multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); - - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); - - expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); - }); -}); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts deleted file mode 100644 index 6494ed24a59..00000000000 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { toHex } from '@metamask/controller-utils'; -import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; -import type { NetworkController } from '@metamask/network-controller'; -import SafeEventEmitter from '@metamask/safe-event-emitter'; -import type { CaipChainId, Hex } from '@metamask/utils'; -import { parseCaipChainId } from '@metamask/utils'; -import type EventEmitter from 'events'; - -import type { ExternalScopeString } from '../scope/types'; - -export type SubscriptionManager = { - events: EventEmitter; - destroy?: () => void; -}; - -type SubscriptionNotificationEvent = { - jsonrpc: '2.0'; - method: 'eth_subscription'; - params: { - subscription: Hex; - result: unknown; - }; -}; - -type SubscriptionKey = { - scope: ExternalScopeString; - origin: string; - tabId?: number; -}; -type SubscriptionEntry = SubscriptionKey & { - subscriptionManager: SubscriptionManager; -}; - -type MultichainSubscriptionManagerOptions = { - findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; - getNetworkClientById: NetworkController['getNetworkClientById']; -}; - -export class MultichainSubscriptionManager extends SafeEventEmitter { - #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; - - #getNetworkClientById: NetworkController['getNetworkClientById']; - - #subscriptions: SubscriptionEntry[] = []; - - constructor(options: MultichainSubscriptionManagerOptions) { - super(); - this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId; - this.#getNetworkClientById = options.getNetworkClientById; - } - - onNotification( - { scope, origin, tabId }: SubscriptionKey, - { method, params }: SubscriptionNotificationEvent, - ) { - this.emit('notification', origin, tabId, { - method: 'wallet_notify', - params: { - scope, - notification: { method, params }, - }, - }); - } - - #getSubscriptionEntry({ - scope, - origin, - tabId, - }: SubscriptionKey): SubscriptionEntry | undefined { - return this.#subscriptions.find((subscriptionEntry) => { - return ( - subscriptionEntry.scope === scope && - subscriptionEntry.origin === origin && - subscriptionEntry.tabId === tabId - ); - }); - } - - #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionKey) { - this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => { - return ( - subscriptionEntry.scope !== scope || - subscriptionEntry.origin !== origin || - subscriptionEntry.tabId !== tabId - ); - }); - } - - subscribe(subscriptionKey: SubscriptionKey) { - const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey); - if (subscriptionEntry) { - return subscriptionEntry.subscriptionManager; - } - - const networkClientId = this.#findNetworkClientIdByChainId( - toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference), - ); - const networkClient = this.#getNetworkClientById(networkClientId); - const subscriptionManager = createSubscriptionManager({ - blockTracker: networkClient.blockTracker, - provider: networkClient.provider, - }); - - subscriptionManager.events.on( - 'notification', - (message: SubscriptionNotificationEvent) => { - this.onNotification(subscriptionKey, message); - }, - ); - - this.#subscriptions.push({ - ...subscriptionKey, - subscriptionManager, - }); - - return subscriptionManager; - } - - #unsubscribe(subscriptionKey: SubscriptionKey) { - const existingSubscriptionEntry = - this.#getSubscriptionEntry(subscriptionKey); - if (!existingSubscriptionEntry) { - return; - } - - existingSubscriptionEntry.subscriptionManager.destroy?.(); - - this.#removeSubscriptionEntry(subscriptionKey); - } - - unsubscribeByScope(scope: ExternalScopeString) { - this.#subscriptions.forEach((subscriptionEntry) => { - if (subscriptionEntry.scope === scope) { - this.#unsubscribe(subscriptionEntry); - } - }); - } - - unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) { - this.#subscriptions.forEach((subscriptionEntry) => { - if ( - subscriptionEntry.scope === scope && - subscriptionEntry.origin === origin - ) { - this.#unsubscribe(subscriptionEntry); - } - }); - } - - unsubscribeByOriginAndTabId(origin: string, tabId?: number) { - this.#subscriptions.forEach((subscriptionEntry) => { - if ( - subscriptionEntry.origin === origin && - subscriptionEntry.tabId === tabId - ) { - this.#unsubscribe(subscriptionEntry); - } - }); - } -} diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts deleted file mode 100644 index d62b2328eba..00000000000 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; -import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; -import { rpcErrors } from '@metamask/rpc-errors'; -import { isObject } from '@metamask/utils'; -import type { - Json, - JsonRpcError, - JsonRpcParams, - JsonRpcRequest, -} from '@metamask/utils'; -import type { - ContentDescriptorObject, - MethodObject, - OpenrpcDocument, -} from '@open-rpc/meta-schema'; -import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; -import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; -import type { Schema, ValidationError } from 'jsonschema'; -import { Validator } from 'jsonschema'; - -const transformError = ( - error: ValidationError, - param: ContentDescriptorObject, - got: unknown, -) => { - // if there is a path, add it to the message - const message = `${ - param.name + (error.path.length > 0 ? `.${error.path.join('.')}` : '') - } ${error.message}`; - - return { - code: -32602, // TODO: could be a different error code or not wrapped in json-rpc error, since this will also be wrapped in a -32602 invalid params error - message, - data: { - param: param.name, - path: error.path, - schema: error.schema, - got, - }, - }; -}; - -const v = new Validator(); - -const dereffedPromise = dereferenceDocument( - MultiChainOpenRPCDocument as unknown as OpenrpcDocument, - makeCustomResolver({}), -); -const multichainMethodCallValidator = async ( - method: string, - params: JsonRpcParams | undefined, -) => { - const dereffed = await dereffedPromise; - const methodToCheck = dereffed.methods.find( - (m) => (m as unknown as ContentDescriptorObject).name === method, - ); - const errors: JsonRpcError[] = []; - // check each param and aggregate errors - (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { - let paramToCheck: Json | undefined; - const p = param as ContentDescriptorObject; - if (isObject(params)) { - paramToCheck = params[p.name]; - } else if (params && Array.isArray(params)) { - paramToCheck = params[i]; - } else { - paramToCheck = undefined; - } - const result = v.validate(paramToCheck, p.schema as unknown as Schema, { - required: p.required, - }); - if (result.errors) { - errors.push( - ...result.errors.map((e) => { - return transformError(e, p, paramToCheck) as JsonRpcError; - }), - ); - } - }); - if (errors.length > 0) { - return errors; - } - // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors - // would be an array and return true if it's empty - return false; -}; - -export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< - JsonRpcRequest, - Json -> = function (request, _response, next, end) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - multichainMethodCallValidator(request.method, request.params).then( - (errors) => { - if (errors) { - return end(rpcErrors.invalidParams({ data: errors })); - } - return next(); - }, - ); -}; diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 4c8bc65e7fb..55a184b364a 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,5 +1,4 @@ -import { bucketScopes, validateAndNormalizeScopes } from './authorization'; -import * as Filter from './filter'; +import { validateAndNormalizeScopes } from './authorization'; import * as Transform from './transform'; import type { ExternalScopeObject } from './types'; import * as Validation from './validation'; @@ -14,11 +13,6 @@ jest.mock('./transform', () => ({ })); const MockTransform = jest.mocked(Transform); -jest.mock('./filter', () => ({ - bucketScopesBySupport: jest.fn(), -})); -const MockFilter = jest.mocked(Filter); - const validScopeObject: ExternalScopeObject = { methods: [], notifications: [], @@ -98,129 +92,4 @@ describe('Scope Authorization', () => { }); }); }); - - describe('bucketScopes', () => { - beforeEach(() => { - let callCount = 0; - MockFilter.bucketScopesBySupport.mockImplementation(() => { - callCount += 1; - return { - supportedScopes: { - 'mock:A': { - methods: [`mock_method_${callCount}`], - notifications: [], - accounts: [], - }, - }, - unsupportedScopes: { - 'mock:B': { - methods: [`mock_method_${callCount}`], - notifications: [], - accounts: [], - }, - }, - }; - }); - }); - - it('buckets the scopes by supported', () => { - const isChainIdSupported = jest.fn(); - bucketScopes( - { - wallet: { - methods: [], - notifications: [], - accounts: [], - }, - }, - { - isChainIdSupported, - isChainIdSupportable: jest.fn(), - }, - ); - - expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( - { - wallet: { - methods: [], - notifications: [], - accounts: [], - }, - }, - { - isChainIdSupported, - }, - ); - }); - - it('buckets the mayble supportable scopes', () => { - const isChainIdSupportable = jest.fn(); - bucketScopes( - { - wallet: { - methods: [], - notifications: [], - accounts: [], - }, - }, - { - isChainIdSupported: jest.fn(), - isChainIdSupportable, - }, - ); - - expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( - { - 'mock:B': { - methods: [`mock_method_1`], - notifications: [], - accounts: [], - }, - }, - { - isChainIdSupported: isChainIdSupportable, - }, - ); - }); - - it('returns the bucketed scopes', () => { - expect( - bucketScopes( - { - wallet: { - methods: [], - notifications: [], - accounts: [], - }, - }, - { - isChainIdSupported: jest.fn(), - isChainIdSupportable: jest.fn(), - }, - ), - ).toStrictEqual({ - supportedScopes: { - 'mock:A': { - methods: [`mock_method_1`], - notifications: [], - accounts: [], - }, - }, - supportableScopes: { - 'mock:A': { - methods: [`mock_method_2`], - notifications: [], - accounts: [], - }, - }, - unsupportableScopes: { - 'mock:B': { - methods: [`mock_method_2`], - notifications: [], - accounts: [], - }, - }, - }); - }); - }); }); diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index 3dcbef7e40d..c7b98a83570 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,6 +1,3 @@ -import type { Hex } from '@metamask/utils'; - -import { bucketScopesBySupport } from './filter'; import { normalizeAndMergeScopes } from './transform'; import type { ExternalScopesObject, ScopesObject } from './types'; import { validateScopes } from './validation'; @@ -38,32 +35,3 @@ export const validateAndNormalizeScopes = ( normalizedOptionalScopes, }; }; - -export const bucketScopes = ( - scopes: ScopesObject, - { - isChainIdSupported, - isChainIdSupportable, - }: { - isChainIdSupported: (chainId: Hex) => boolean; - isChainIdSupportable: (chainId: Hex) => boolean; - }, -): { - supportedScopes: ScopesObject; - supportableScopes: ScopesObject; - unsupportableScopes: ScopesObject; -} => { - const { supportedScopes, unsupportedScopes: maybeSupportableScopes } = - bucketScopesBySupport(scopes, { - isChainIdSupported, - }); - - const { - supportedScopes: supportableScopes, - unsupportedScopes: unsupportableScopes, - } = bucketScopesBySupport(maybeSupportableScopes, { - isChainIdSupported: isChainIdSupportable, - }); - - return { supportedScopes, supportableScopes, unsupportableScopes }; -}; diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts deleted file mode 100644 index c49c7397864..00000000000 --- a/packages/multichain/src/scope/filter.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import * as Assert from './assert'; -import { filterScopesSupported, bucketScopesBySupport } from './filter'; - -jest.mock('./assert', () => ({ - assertScopeSupported: jest.fn(), -})); -const MockAssert = jest.mocked(Assert); - -describe('filter', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - - describe('filterScopesSupported', () => { - const isChainIdSupported = jest.fn(); - - it('checks if each scope is supported', () => { - filterScopesSupported( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ); - - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:1', - { - methods: ['a'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:5', - { - methods: ['b'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - }); - - it('returns only supported scopes', () => { - MockAssert.assertScopeSupported.mockImplementation((scopeString) => { - if (scopeString === 'eip155:1') { - throw new Error('scope not supported'); - } - }); - - expect( - filterScopesSupported( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ), - ).toStrictEqual({ - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }); - }); - }); - - describe('bucketScopesBySupport', () => { - const isChainIdSupported = jest.fn(); - - it('checks if each scope is supported', () => { - bucketScopesBySupport( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ); - - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:1', - { - methods: ['a'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:5', - { - methods: ['b'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - }); - - it('returns supported and unsupported scopes', () => { - MockAssert.assertScopeSupported.mockImplementation((scopeString) => { - if (scopeString === 'eip155:1') { - throw new Error('scope not supported'); - } - }); - - expect( - bucketScopesBySupport( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ), - ).toStrictEqual({ - supportedScopes: { - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - unsupportedScopes: { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - }, - }); - }); - }); -}); diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts deleted file mode 100644 index 58157bd6027..00000000000 --- a/packages/multichain/src/scope/filter.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { CaipChainId, Hex } from '@metamask/utils'; - -import { assertScopeSupported } from './assert'; -import type { ScopesObject } from './types'; - -export const bucketScopesBySupport = ( - scopes: ScopesObject, - { - isChainIdSupported, - }: { - isChainIdSupported: (chainId: Hex) => boolean; - }, -) => { - const supportedScopes: ScopesObject = {}; - const unsupportedScopes: ScopesObject = {}; - - for (const [scopeString, scopeObject] of Object.entries(scopes)) { - try { - assertScopeSupported(scopeString, scopeObject, { - isChainIdSupported, - }); - supportedScopes[scopeString as CaipChainId] = scopeObject; - } catch (err) { - unsupportedScopes[scopeString as CaipChainId] = scopeObject; - } - } - - return { supportedScopes, unsupportedScopes }; -}; - -export const filterScopesSupported = ( - scopes: ScopesObject, - { - isChainIdSupported, - }: { - isChainIdSupported: (chainId: Hex) => boolean; - }, -) => { - const { supportedScopes } = bucketScopesBySupport(scopes, { - isChainIdSupported, - }); - - return supportedScopes; -}; From 4ceb11850f8bc7340290940204f3e2a4a4f30db9 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:12:11 -0700 Subject: [PATCH 039/146] remove api related deps --- packages/multichain/package.json | 5 -- yarn.lock | 123 +------------------------------ 2 files changed, 3 insertions(+), 125 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 044b203f0ba..313c94a52f6 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -51,18 +51,13 @@ "@metamask/controller-utils": "^11.3.0", "@metamask/eth-json-rpc-filters": "^7.0.0", "@metamask/rpc-errors": "^7.0.0", - "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^9.1.0", - "@open-rpc/schema-utils-js": "^2.0.5", - "jsonschema": "^1.2.4", "lodash": "^4.17.21" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", - "@metamask/json-rpc-engine": "^9.0.3", "@metamask/network-controller": "^21.0.1", "@metamask/permission-controller": "^11.0.2", - "@open-rpc/meta-schema": "^1.14.6", "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", "jest": "^27.5.1", diff --git a/yarn.lock b/yarn.lock index 31ab2d0d9ec..b16e5d8f3e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1931,48 +1931,6 @@ __metadata: languageName: node linkType: hard -"@json-schema-spec/json-pointer@npm:^0.1.2": - version: 0.1.2 - resolution: "@json-schema-spec/json-pointer@npm:0.1.2" - checksum: 10/2a691ffc11f1a266ca4d0c9e2c99791679d580f343ef69746fad623d1abcf4953adde987890e41f906767d7729604c0182341e9012388b73a44d5b21fb296453 - languageName: node - linkType: hard - -"@json-schema-tools/dereferencer@npm:^1.6.3": - version: 1.6.3 - resolution: "@json-schema-tools/dereferencer@npm:1.6.3" - dependencies: - "@json-schema-tools/reference-resolver": "npm:^1.2.6" - "@json-schema-tools/traverse": "npm:^1.10.4" - fast-safe-stringify: "npm:^2.1.1" - checksum: 10/da6ef5b82a8a9c3a7e62ffcab5c04c581f1e0f8165c0debdb272bb1e08ccd726107ee194487b8fa736cac00fb390b8df74bc1ad1b200eddbe25c98ee0d3d000b - languageName: node - linkType: hard - -"@json-schema-tools/meta-schema@npm:^1.7.5": - version: 1.7.5 - resolution: "@json-schema-tools/meta-schema@npm:1.7.5" - checksum: 10/707dc3a285c26c37d00f418e9d0ef8a2ad1c23d4936ad5aab0ce94c9ae36a7a6125c4ca5048513af64b7e6e527b5472a1701d1f709c379acdd7ad12f6409d2cd - languageName: node - linkType: hard - -"@json-schema-tools/reference-resolver@npm:^1.2.6": - version: 1.2.6 - resolution: "@json-schema-tools/reference-resolver@npm:1.2.6" - dependencies: - "@json-schema-spec/json-pointer": "npm:^0.1.2" - isomorphic-fetch: "npm:^3.0.0" - checksum: 10/91d6b4b2ac43f8163fd27bde6d826f29f339e9c7ce3b7e2b73b85e891fa78e3702fd487deda143a0701879cbc2fe28c53a4efce4cd2d2dd2fe6e82b64bbd9c9c - languageName: node - linkType: hard - -"@json-schema-tools/traverse@npm:^1.10.4": - version: 1.10.4 - resolution: "@json-schema-tools/traverse@npm:1.10.4" - checksum: 10/0027bc90df01c5eeee0833e722b7320b53be8b5ce3f4e0e4a6e45713a38e6f88f21aba31e3dd973093ef75cd21a40c07fe8f112da8f49a7919b1c0e44c904d20 - languageName: node - linkType: hard - "@keystonehq/alias-sampling@npm:^0.1.1": version: 0.1.2 resolution: "@keystonehq/alias-sampling@npm:0.1.2" @@ -3102,18 +3060,13 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/controller-utils": "npm:^11.3.0" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" - "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" "@metamask/rpc-errors": "npm:^7.0.0" - "@metamask/safe-event-emitter": "npm:^3.0.0" "@metamask/utils": "npm:^9.1.0" - "@open-rpc/meta-schema": "npm:^1.14.6" - "@open-rpc/schema-utils-js": "npm:^2.0.5" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" - jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" @@ -4075,31 +4028,6 @@ __metadata: languageName: node linkType: hard -"@open-rpc/meta-schema@npm:^1.14.6, @open-rpc/meta-schema@npm:^1.14.9": - version: 1.14.9 - resolution: "@open-rpc/meta-schema@npm:1.14.9" - checksum: 10/51505dcf7aa1a2285c78953c9b33711cede5f2765aa37dcb9ee7756d689e2ff2a89cfc6039504f0569c52a805fb9aa18f30a7c02ad7a06e793c801e43b419104 - languageName: node - linkType: hard - -"@open-rpc/schema-utils-js@npm:^2.0.5": - version: 2.0.5 - resolution: "@open-rpc/schema-utils-js@npm:2.0.5" - dependencies: - "@json-schema-tools/dereferencer": "npm:^1.6.3" - "@json-schema-tools/meta-schema": "npm:^1.7.5" - "@json-schema-tools/reference-resolver": "npm:^1.2.6" - "@open-rpc/meta-schema": "npm:^1.14.9" - ajv: "npm:^6.10.0" - detect-node: "npm:^2.0.4" - fast-safe-stringify: "npm:^2.0.7" - fs-extra: "npm:^10.1.0" - is-url: "npm:^1.2.4" - isomorphic-fetch: "npm:^3.0.0" - checksum: 10/9e10215606e9a00a47b082c9cfd70d05bf0d38de6cf1c147246c545c6997375d94cd3caafe919b71178df58b5facadfd0dcc8b6857bf5e79c40e5e33683dd3d5 - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -5040,7 +4968,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.4": +"ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -6436,13 +6364,6 @@ __metadata: languageName: node linkType: hard -"detect-node@npm:^2.0.4": - version: 2.1.0 - resolution: "detect-node@npm:2.1.0" - checksum: 10/832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e - languageName: node - linkType: hard - "diff-sequences@npm:^27.5.1": version: 27.5.1 resolution: "diff-sequences@npm:27.5.1" @@ -7451,7 +7372,7 @@ __metadata: languageName: node linkType: hard -"fast-safe-stringify@npm:^2.0.6, fast-safe-stringify@npm:^2.0.7, fast-safe-stringify@npm:^2.1.1": +"fast-safe-stringify@npm:^2.0.6": version: 2.1.1 resolution: "fast-safe-stringify@npm:2.1.1" checksum: 10/dc1f063c2c6ac9533aee14d406441f86783a8984b2ca09b19c2fe281f9ff59d315298bc7bc22fd1f83d26fe19ef2f20e2ddb68e96b15040292e555c5ced0c1e4 @@ -7691,17 +7612,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^10.1.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10/05ce2c3b59049bcb7b52001acd000e44b3c4af4ec1f8839f383ef41ec0048e3cfa7fd8a637b1bddfefad319145db89be91f4b7c1db2908205d38bf91e7d1d3b7 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -7995,7 +7905,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -8671,13 +8581,6 @@ __metadata: languageName: node linkType: hard -"is-url@npm:^1.2.4": - version: 1.2.4 - resolution: "is-url@npm:1.2.4" - checksum: 10/100e74b3b1feab87a43ef7653736e88d997eb7bd32e71fd3ebc413e58c1cbe56269699c776aaea84244b0567f2a7d68dfaa512a062293ed2f9fdecb394148432 - languageName: node - linkType: hard - "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -9614,19 +9517,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: "npm:^4.1.6" - universalify: "npm:^2.0.0" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10/03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 - languageName: node - linkType: hard - "jsonschema@npm:^1.2.4": version: 1.4.1 resolution: "jsonschema@npm:1.4.1" @@ -12454,13 +12344,6 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^2.0.0": - version: 2.0.1 - resolution: "universalify@npm:2.0.1" - checksum: 10/ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" From a36ec4d1c6fc11e23bf13f36a43d8f9501403758 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:12:44 -0700 Subject: [PATCH 040/146] Revert "remove API related logic" This reverts commit fc28c89c17de6e9593c6551cd159ebd10587489c. --- .../src/handlers/wallet-getSession.test.ts | 117 ++++++++ .../src/handlers/wallet-getSession.ts | 66 ++++ .../src/handlers/wallet-invokeMethod.test.ts | 282 ++++++++++++++++++ .../src/handlers/wallet-invokeMethod.ts | 120 ++++++++ .../src/handlers/wallet-revokeSession.test.ts | 92 ++++++ .../src/handlers/wallet-revokeSession.ts | 54 ++++ packages/multichain/src/index.test.ts | 11 + packages/multichain/src/index.ts | 11 + .../MultichainMiddlewareManager.test.ts | 171 +++++++++++ .../MultichainMiddlewareManager.ts | 137 +++++++++ .../MultichainSubscriptionManager.test.ts | 120 ++++++++ .../MultichainSubscriptionManager.ts | 160 ++++++++++ .../multichainMethodCallValidator.ts | 101 +++++++ .../src/scope/authorization.test.ts | 133 ++++++++- .../multichain/src/scope/authorization.ts | 32 ++ packages/multichain/src/scope/filter.test.ts | 168 +++++++++++ packages/multichain/src/scope/filter.ts | 44 +++ 17 files changed, 1818 insertions(+), 1 deletion(-) create mode 100644 packages/multichain/src/handlers/wallet-getSession.test.ts create mode 100644 packages/multichain/src/handlers/wallet-getSession.ts create mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.test.ts create mode 100644 packages/multichain/src/handlers/wallet-invokeMethod.ts create mode 100644 packages/multichain/src/handlers/wallet-revokeSession.test.ts create mode 100644 packages/multichain/src/handlers/wallet-revokeSession.ts create mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts create mode 100644 packages/multichain/src/middlewares/MultichainMiddlewareManager.ts create mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts create mode 100644 packages/multichain/src/middlewares/MultichainSubscriptionManager.ts create mode 100644 packages/multichain/src/middlewares/multichainMethodCallValidator.ts create mode 100644 packages/multichain/src/scope/filter.test.ts create mode 100644 packages/multichain/src/scope/filter.ts diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts new file mode 100644 index 00000000000..ca74cc9b909 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -0,0 +1,117 @@ +import type { JsonRpcRequest } from '@metamask/utils'; + +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { walletGetSession } from './wallet-getSession'; + +const baseRequest: JsonRpcRequest & { origin: string } = { + origin: 'http://test.com', + jsonrpc: '2.0' as const, + method: 'wallet_getSession', + params: {}, + id: 1, +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: ['chainChanged'], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + }, + }, + }); + const response = { + result: { + sessionScopes: {}, + }, + id: 1, + jsonrpc: '2.0' as const, + }; + const handler = (request: JsonRpcRequest & { origin: string }) => + walletGetSession.implementation(request, response, next, end, { + getCaveat, + }); + + return { + next, + response, + end, + getCaveat, + handler, + }; +}; + +describe('wallet_getSession', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const { handler, getCaveat } = createMockedHandler(); + + await handler(baseRequest); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('returns empty scopes if the CAIP-25 endowment permission does not exist', async () => { + const { handler, response, getCaveat } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + + await handler(baseRequest); + expect(response.result).toStrictEqual({ + sessionScopes: {}, + }); + }); + + it('returns the merged scopes', async () => { + const { handler, response } = createMockedHandler(); + + await handler(baseRequest); + expect(response.result).toStrictEqual({ + sessionScopes: { + 'eip155:1': { + methods: ['eth_call', 'net_version'], + notifications: ['chainChanged'], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + }, + }); + }); +}); diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts new file mode 100644 index 00000000000..ad3e4e5569b --- /dev/null +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -0,0 +1,66 @@ +import type { Caveat } from '@metamask/permission-controller'; +import type { JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; +import type { ScopesObject } from '../scope/types'; + +/** + * Handler for the `wallet_getSession` RPC method. + * + * @param request - The request object. + * @param response - The response object. + * @param _next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - Function to retrieve a caveat. + */ +async function walletGetSessionHandler( + request: JsonRpcRequest & { origin: string }, + response: JsonRpcSuccess<{ sessionScopes: ScopesObject }>, + _next: () => void, + end: () => void, + hooks: { + getCaveat: ( + origin: string, + endowmentPermissionName: string, + caveatType: string, + ) => Caveat; + }, +) { + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (e) { + // noop + } + + if (!caveat) { + response.result = { sessionScopes: {} }; + return end(); + } + + response.result = { + sessionScopes: mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + ), + }; + return end(); +} + +export const walletGetSession = { + methodNames: ['wallet_getSession'], + implementation: walletGetSessionHandler, + hookNames: { + getCaveat: true, + }, +}; diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts new file mode 100644 index 00000000000..208bccc3371 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -0,0 +1,282 @@ +import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { walletInvokeMethod } from './wallet-invokeMethod'; + +const createMockedRequest = () => ({ + jsonrpc: '2.0' as const, + id: 0, + origin: 'http://test.com', + method: 'wallet_invokeMethod', + params: { + scope: 'eip155:1', + request: { + method: 'eth_call', + params: { + foo: 'bar', + }, + }, + }, +}); + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: [], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + unhandled: { + methods: ['foobar'], + notifications: [], + accounts: [], + }, + }, + isMultichainOrigin: true, + }, + }); + const findNetworkClientIdByChainId = jest.fn().mockReturnValue('mainnet'); + const getSelectedNetworkClientId = jest + .fn() + .mockReturnValue('selectedNetworkClientId'); + const handler = (request: JsonRpcRequest & { origin: string }) => + walletInvokeMethod.implementation( + request, + { jsonrpc: '2.0', id: 1 }, + next, + end, + { + getCaveat, + findNetworkClientIdByChainId, + getSelectedNetworkClientId, + }, + ); + + return { + next, + end, + getCaveat, + findNetworkClientIdByChainId, + getSelectedNetworkClientId, + handler, + }; +}; + +describe('wallet_invokeMethod', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const request = createMockedRequest(); + const { handler, getCaveat } = createMockedHandler(); + await handler(request); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('throws an unauthorized error when there is no CAIP-25 endowment permission', async () => { + const request = createMockedRequest(); + const { handler, getCaveat, end } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + await handler(request); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error when the CAIP-25 endowment permission was not granted from the multichain flow', async () => { + const request = createMockedRequest(); + const { handler, getCaveat, end } = createMockedHandler(); + getCaveat.mockReturnValue({ + value: { + isMultichainOrigin: false, + }, + }); + await handler(request); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error if the requested scope is not authorized', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'eip155:999', + }, + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an unauthorized error if the requested scope method is not authorized', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + request: { + ...request.params.request, + method: 'unauthorized_method', + }, + }, + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('throws an internal error for authorized but unhandled scopes', async () => { + const request = createMockedRequest(); + const { handler, end } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'unhandled', + request: { + ...request.params.request, + method: 'foobar', + }, + }, + }); + + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + describe('ethereum scope', () => { + it('gets the networkClientId for the chainId', async () => { + const request = createMockedRequest(); + const { handler, findNetworkClientIdByChainId } = createMockedHandler(); + + await handler(request); + expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); + }); + + it('throws an internal error if a networkClientId does not exist for the chainId', async () => { + const request = createMockedRequest(); + const { handler, findNetworkClientIdByChainId, end } = + createMockedHandler(); + findNetworkClientIdByChainId.mockReturnValue(undefined); + + await handler(request); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('sets the networkClientId and unwraps the CAIP-27 request', async () => { + const request = createMockedRequest(); + const { handler, next } = createMockedHandler(); + + await handler(request); + expect(request).toStrictEqual({ + jsonrpc: '2.0' as const, + id: 0, + scope: 'eip155:1', + origin: 'http://test.com', + networkClientId: 'mainnet', + method: 'eth_call', + params: { + foo: 'bar', + }, + }); + expect(next).toHaveBeenCalled(); + }); + }); + + describe('wallet scope', () => { + it('gets the networkClientId for the globally selected network', async () => { + const request = createMockedRequest(); + const { handler, getSelectedNetworkClientId } = createMockedHandler(); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }); + expect(getSelectedNetworkClientId).toHaveBeenCalled(); + }); + + it('throws an internal error if a networkClientId cannot be retrieved for the globally selected network', async () => { + const request = createMockedRequest(); + const { handler, getSelectedNetworkClientId, end } = + createMockedHandler(); + getSelectedNetworkClientId.mockReturnValue(undefined); + + await handler({ + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('sets the networkClientId and unwraps the CAIP-27 request', async () => { + const request = createMockedRequest(); + const { handler, next } = createMockedHandler(); + + const walletRequest = { + ...request, + params: { + ...request.params, + scope: 'wallet', + request: { + ...request.params.request, + method: 'wallet_watchAsset', + }, + }, + }; + await handler(walletRequest); + expect(walletRequest).toStrictEqual({ + jsonrpc: '2.0' as const, + id: 0, + scope: 'wallet', + origin: 'http://test.com', + networkClientId: 'selectedNetworkClientId', + method: 'wallet_watchAsset', + params: { + foo: 'bar', + }, + }); + expect(next).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts new file mode 100644 index 00000000000..3df3ca8346f --- /dev/null +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -0,0 +1,120 @@ +import type { Caveat } from '@metamask/permission-controller'; +import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; +import type { + Json, + JsonRpcRequest, + PendingJsonRpcResponse, +} from '@metamask/utils'; +import { numberToHex } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; +import type { ScopeString } from '../scope/types'; +import { parseScopeString } from '../scope/types'; + +/** + * Handler for the `wallet_invokeMethod` RPC method. + * + * @param request - The request object. + * @param _response - The response object. + * @param next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - the hook for getting a caveat from a permission for an origin. + * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId. + * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. + */ +async function walletInvokeMethodHandler( + request: JsonRpcRequest & { origin: string }, + _response: PendingJsonRpcResponse, + next: () => void, + end: (error: Error) => void, + hooks: { + getCaveat: ( + origin: string, + endowmentPermissionName: string, + caveatType: string, + ) => Caveat; + findNetworkClientIdByChainId: (chainId: string) => string | undefined; + getSelectedNetworkClientId: () => string; + }, +) { + const { scope, request: wrappedRequest } = request.params as { + scope: ScopeString; + request: JsonRpcRequest; + }; + + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (e) { + // noop + } + if (!caveat?.value?.isMultichainOrigin) { + return end(providerErrors.unauthorized()); + } + + const scopeObject = mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + )[scope]; + + if (!scopeObject?.methods?.includes(wrappedRequest.method)) { + return end(providerErrors.unauthorized()); + } + + const { namespace, reference } = parseScopeString(scope); + + let networkClientId; + switch (namespace) { + case 'wallet': + networkClientId = hooks.getSelectedNetworkClientId(); + break; + case 'eip155': + if (reference) { + networkClientId = hooks.findNetworkClientIdByChainId( + numberToHex(parseInt(reference, 10)), + ); + } + break; + default: + console.error( + 'failed to resolve namespace for wallet_invokeMethod', + request, + ); + return end(rpcErrors.internal()); + } + + if (!networkClientId) { + console.error( + 'failed to resolve network client for wallet_invokeMethod', + request, + ); + return end(rpcErrors.internal()); + } + + Object.assign(request, { + scope, + networkClientId, + method: wrappedRequest.method, + params: wrappedRequest.params, + }); + return next(); +} +export const walletInvokeMethod = { + methodNames: ['wallet_invokeMethod'], + implementation: walletInvokeMethodHandler, + hookNames: { + getCaveat: true, + findNetworkClientIdByChainId: true, + getSelectedNetworkClientId: true, + }, +}; diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.ts b/packages/multichain/src/handlers/wallet-revokeSession.test.ts new file mode 100644 index 00000000000..e11b89f42c2 --- /dev/null +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.ts @@ -0,0 +1,92 @@ +import { + PermissionDoesNotExistError, + UnrecognizedSubjectError, +} from '@metamask/permission-controller'; +import { rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + +import { Caip25EndowmentPermissionName } from '../caip25Permission'; +import { walletRevokeSession } from './wallet-revokeSession'; + +const baseRequest: JsonRpcRequest & { origin: string } = { + origin: 'http://test.com', + params: {}, + jsonrpc: '2.0' as const, + id: 1, + method: 'wallet_revokeSession', +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const revokePermission = jest.fn(); + const response = { + result: true, + id: 1, + jsonrpc: '2.0' as const, + }; + const handler = (request: JsonRpcRequest & { origin: string }) => + walletRevokeSession.implementation(request, response, next, end, { + revokePermission, + }); + + return { + next, + response, + end, + revokePermission, + handler, + }; +}; + +describe('wallet_revokeSession', () => { + it('revokes the the CAIP-25 endowment permission', async () => { + const { handler, revokePermission } = createMockedHandler(); + + await handler(baseRequest); + expect(revokePermission).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + ); + }); + + it('returns true if the CAIP-25 endowment permission does not exist', async () => { + const { handler, response, revokePermission } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new PermissionDoesNotExistError( + 'foo.com', + Caip25EndowmentPermissionName, + ); + }); + + await handler(baseRequest); + expect(response.result).toBe(true); + }); + + it('returns true if the subject does not exist', async () => { + const { handler, response, revokePermission } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new UnrecognizedSubjectError('foo.com'); + }); + + await handler(baseRequest); + expect(response.result).toBe(true); + }); + + it('throws an internal RPC error if something unexpected goes wrong with revoking the permission', async () => { + const { handler, revokePermission, end } = createMockedHandler(); + revokePermission.mockImplementation(() => { + throw new Error('revoke failed'); + }); + + await handler(baseRequest); + expect(end).toHaveBeenCalledWith(rpcErrors.internal()); + }); + + it('returns true if the permission was revoked', async () => { + const { handler, response } = createMockedHandler(); + + await handler(baseRequest); + expect(response.result).toBe(true); + }); +}); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts new file mode 100644 index 00000000000..51e31073f0d --- /dev/null +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -0,0 +1,54 @@ +import type { + JsonRpcEngineNextCallback, + JsonRpcEngineEndCallback, +} from '@metamask/json-rpc-engine'; +import { + PermissionDoesNotExistError, + UnrecognizedSubjectError, +} from '@metamask/permission-controller'; +import { rpcErrors } from '@metamask/rpc-errors'; +import type { JsonRpcSuccess, Json, JsonRpcRequest } from '@metamask/utils'; + +import { Caip25EndowmentPermissionName } from '../caip25Permission'; + +/** + * Handles the `wallet_revokeSession` RPC method. + * + * @param request - The JSON-RPC request object. + * @param response - The JSON-RPC response object. + * @param _next - The next middleware function. + * @param end - The end callback function. + * @param hooks - The hooks object. + * @param hooks.revokePermission - The revokePermission function. + */ +async function walletRevokeSessionHandler( + request: JsonRpcRequest & { origin: string }, + response: JsonRpcSuccess, + _next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + hooks: { + revokePermission: (origin: string, permissionName: string) => void; + }, +) { + try { + hooks.revokePermission(request.origin, Caip25EndowmentPermissionName); + } catch (err) { + if ( + !(err instanceof UnrecognizedSubjectError) && + !(err instanceof PermissionDoesNotExistError) + ) { + console.error(err); + return end(rpcErrors.internal()); + } + } + + response.result = true; + return end(); +} +export const walletRevokeSession = { + methodNames: ['wallet_revokeSession'], + implementation: walletRevokeSessionHandler, + hookNames: { + revokePermission: true, + }, +}; diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 7cf4f393210..d06cd6094eb 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -10,7 +10,18 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", + "walletGetSession", + "walletInvokeMethod", + "walletRevokeSession", + "multichainMethodCallValidatorMiddleware", + "MultichainMiddlewareManager", + "MultichainSubscriptionManager", + "assertScopeSupported", + "assertScopesSupported", "validateAndNormalizeScopes", + "bucketScopes", + "bucketScopesBySupport", + "filterScopesSupported", "isSupportedScopeString", "isSupportedAccount", "isSupportedMethod", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 47a6b90661f..f46f4c97c74 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -10,10 +10,21 @@ export { setPermittedEthChainIds, } from './adapters/caip-permission-adapter-permittedChains'; +export { walletGetSession } from './handlers/wallet-getSession'; +export { walletInvokeMethod } from './handlers/wallet-invokeMethod'; +export { walletRevokeSession } from './handlers/wallet-revokeSession'; + +export { multichainMethodCallValidatorMiddleware } from './middlewares/multichainMethodCallValidator'; +export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager'; +export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager'; + +export { assertScopeSupported, assertScopesSupported } from './scope/assert'; export type { Caip25Authorization } from './scope/authorization'; export { validateAndNormalizeScopes, + bucketScopes, } from './scope/authorization'; +export { bucketScopesBySupport, filterScopesSupported } from './scope/filter'; export * from './scope/types'; export { isSupportedScopeString, diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts new file mode 100644 index 00000000000..4a358896fce --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -0,0 +1,171 @@ +import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; +import { MultichainMiddlewareManager } from './MultichainMiddlewareManager'; + +const scope = 'eip155:1'; +const origin = 'example.com'; +const tabId = 123; + +describe('MultichainMiddlewareManager', () => { + it('should add middleware and get called for the scope, origin, and tabId', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).toHaveBeenCalledWith( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', async () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + await middleware.destroy?.(); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by scope', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByScope(scope); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by scope and origin', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByScopeAndOrigin(scope, origin); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by origin and tabId', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + multichainMiddlewareManager.removeMiddlewareByOriginAndTabId(origin, tabId); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts new file mode 100644 index 00000000000..d1e52f93852 --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -0,0 +1,137 @@ +import type { + JsonRpcEngineEndCallback, + JsonRpcEngineNextCallback, +} from '@metamask/json-rpc-engine'; +import type { + Json, + JsonRpcRequest, + PendingJsonRpcResponse, +} from '@metamask/utils'; + +import type { ExternalScopeString } from '../scope/types'; + +export type ExtendedJsonRpcMiddleware = { + ( + req: JsonRpcRequest & { scope: string }, + res: PendingJsonRpcResponse, + next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + ): void; + destroy?: () => void | Promise; +}; + +type MiddlewareKey = { + scope: ExternalScopeString; + origin: string; + tabId?: number; +}; +type MiddlewareEntry = MiddlewareKey & { + middleware: ExtendedJsonRpcMiddleware; +}; + +export class MultichainMiddlewareManager { + #middlewares: MiddlewareEntry[] = []; + + #getMiddlewareEntry({ + scope, + origin, + tabId, + }: MiddlewareKey): MiddlewareEntry | undefined { + return this.#middlewares.find((middlewareEntry) => { + return ( + middlewareEntry.scope === scope && + middlewareEntry.origin === origin && + middlewareEntry.tabId === tabId + ); + }); + } + + #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareKey) { + this.#middlewares = this.#middlewares.filter((middlewareEntry) => { + return ( + middlewareEntry.scope !== scope || + middlewareEntry.origin !== origin || + middlewareEntry.tabId !== tabId + ); + }); + } + + addMiddleware(middlewareEntry: MiddlewareEntry) { + const { scope, origin, tabId } = middlewareEntry; + if (!this.#getMiddlewareEntry({ scope, origin, tabId })) { + this.#middlewares.push(middlewareEntry); + } + } + + #removeMiddleware(middlewareKey: MiddlewareKey) { + const existingMiddlewareEntry = this.#getMiddlewareEntry(middlewareKey); + if (!existingMiddlewareEntry) { + return; + } + + // When the destroy function on the middleware is async, + // we don't need to wait for it complete + // eslint-disable-next-line no-void + void existingMiddlewareEntry.middleware.destroy?.(); + + this.#removeMiddlewareEntry(middlewareKey); + } + + removeMiddlewareByScope(scope: ExternalScopeString) { + this.#middlewares.forEach((middlewareEntry) => { + if (middlewareEntry.scope === scope) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) { + this.#middlewares.forEach((middlewareEntry) => { + if ( + middlewareEntry.scope === scope && + middlewareEntry.origin === origin + ) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) { + this.#middlewares.forEach((middlewareEntry) => { + if ( + middlewareEntry.origin === origin && + middlewareEntry.tabId === tabId + ) { + this.#removeMiddleware(middlewareEntry); + } + }); + } + + generateMultichainMiddlewareForOriginAndTabId( + origin: string, + tabId?: number, + ) { + const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => { + const { scope } = req; + const middlewareEntry = this.#getMiddlewareEntry({ + scope, + origin, + tabId, + }); + + if (middlewareEntry) { + middlewareEntry.middleware(req, res, next, end); + } else { + return next(); + } + return undefined; + }; + middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind( + this, + origin, + tabId, + ); + + return middleware; + } +} diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts new file mode 100644 index 00000000000..cf05aa5c5a9 --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -0,0 +1,120 @@ +import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; + +import { MultichainSubscriptionManager } from './MultichainSubscriptionManager'; + +jest.mock('@metamask/eth-json-rpc-filters/subscriptionManager', () => + jest.fn(), +); +const MockCreateSubscriptionManager = jest.mocked(createSubscriptionManager); + +const newHeadsNotificationMock = { + method: 'eth_subscription', + params: { + result: { + difficulty: '0x15d9223a23aa', + extraData: '0xd983010305844765746887676f312e342e328777696e646f7773', + gasLimit: '0x47e7c4', + gasUsed: '0x38658', + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + miner: '0xf8b483dba2c3b7176a3da549ad41a48bb3121069', + nonce: '0x084149998194cc5f', + number: '0x1348c9', + parentHash: + '0x7736fab79e05dc611604d22470dadad26f56fe494421b5b333de816ce1f25701', + receiptRoot: + '0x2fab35823ad00c7bb388595cb46652fe7886e00660a01e867824d3dceb1c8d36', + sha3Uncles: + '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + stateRoot: + '0xb3346685172db67de536d8765c43c31009d0eb3bd9c501c9be3229203f15f378', + timestamp: '0x56ffeff8', + }, + }, +}; + +const scope = 'eip155:1'; +const origin = 'example.com'; +const tabId = 123; + +const createMultichainSubscriptionManager = () => { + const mockFindNetworkClientIdByChainId = jest.fn(); + const mockGetNetworkClientById = jest.fn().mockImplementation(() => ({ + blockTracker: {}, + provider: {}, + })); + const multichainSubscriptionManager = new MultichainSubscriptionManager({ + findNetworkClientIdByChainId: mockFindNetworkClientIdByChainId, + getNetworkClientById: mockGetNetworkClientById, + }); + + return { multichainSubscriptionManager }; +}; + +describe('MultichainSubscriptionManager', () => { + const mockSubscriptionManager = { + events: { + on: jest.fn(), + }, + destroy: jest.fn(), + }; + + beforeEach(() => { + MockCreateSubscriptionManager.mockReturnValue(mockSubscriptionManager); + }); + + it('should subscribe to a scope, origin, and tabId', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + const onNotificationSpy = jest.fn(); + multichainSubscriptionManager.on('notification', onNotificationSpy); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(onNotificationSpy).toHaveBeenCalledWith(origin, tabId, { + method: 'wallet_notify', + params: { + scope, + notification: newHeadsNotificationMock, + }, + }); + }); + + it('should unsubscribe from a scope', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByScope(scope); + + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); + }); + + it('should unsubscribe from a scope and origin', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); + }); + + it('should unsubscribe from a origin and tabId', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); + + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); + }); +}); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts new file mode 100644 index 00000000000..6494ed24a59 --- /dev/null +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -0,0 +1,160 @@ +import { toHex } from '@metamask/controller-utils'; +import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; +import type { NetworkController } from '@metamask/network-controller'; +import SafeEventEmitter from '@metamask/safe-event-emitter'; +import type { CaipChainId, Hex } from '@metamask/utils'; +import { parseCaipChainId } from '@metamask/utils'; +import type EventEmitter from 'events'; + +import type { ExternalScopeString } from '../scope/types'; + +export type SubscriptionManager = { + events: EventEmitter; + destroy?: () => void; +}; + +type SubscriptionNotificationEvent = { + jsonrpc: '2.0'; + method: 'eth_subscription'; + params: { + subscription: Hex; + result: unknown; + }; +}; + +type SubscriptionKey = { + scope: ExternalScopeString; + origin: string; + tabId?: number; +}; +type SubscriptionEntry = SubscriptionKey & { + subscriptionManager: SubscriptionManager; +}; + +type MultichainSubscriptionManagerOptions = { + findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; + getNetworkClientById: NetworkController['getNetworkClientById']; +}; + +export class MultichainSubscriptionManager extends SafeEventEmitter { + #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; + + #getNetworkClientById: NetworkController['getNetworkClientById']; + + #subscriptions: SubscriptionEntry[] = []; + + constructor(options: MultichainSubscriptionManagerOptions) { + super(); + this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId; + this.#getNetworkClientById = options.getNetworkClientById; + } + + onNotification( + { scope, origin, tabId }: SubscriptionKey, + { method, params }: SubscriptionNotificationEvent, + ) { + this.emit('notification', origin, tabId, { + method: 'wallet_notify', + params: { + scope, + notification: { method, params }, + }, + }); + } + + #getSubscriptionEntry({ + scope, + origin, + tabId, + }: SubscriptionKey): SubscriptionEntry | undefined { + return this.#subscriptions.find((subscriptionEntry) => { + return ( + subscriptionEntry.scope === scope && + subscriptionEntry.origin === origin && + subscriptionEntry.tabId === tabId + ); + }); + } + + #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionKey) { + this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => { + return ( + subscriptionEntry.scope !== scope || + subscriptionEntry.origin !== origin || + subscriptionEntry.tabId !== tabId + ); + }); + } + + subscribe(subscriptionKey: SubscriptionKey) { + const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey); + if (subscriptionEntry) { + return subscriptionEntry.subscriptionManager; + } + + const networkClientId = this.#findNetworkClientIdByChainId( + toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference), + ); + const networkClient = this.#getNetworkClientById(networkClientId); + const subscriptionManager = createSubscriptionManager({ + blockTracker: networkClient.blockTracker, + provider: networkClient.provider, + }); + + subscriptionManager.events.on( + 'notification', + (message: SubscriptionNotificationEvent) => { + this.onNotification(subscriptionKey, message); + }, + ); + + this.#subscriptions.push({ + ...subscriptionKey, + subscriptionManager, + }); + + return subscriptionManager; + } + + #unsubscribe(subscriptionKey: SubscriptionKey) { + const existingSubscriptionEntry = + this.#getSubscriptionEntry(subscriptionKey); + if (!existingSubscriptionEntry) { + return; + } + + existingSubscriptionEntry.subscriptionManager.destroy?.(); + + this.#removeSubscriptionEntry(subscriptionKey); + } + + unsubscribeByScope(scope: ExternalScopeString) { + this.#subscriptions.forEach((subscriptionEntry) => { + if (subscriptionEntry.scope === scope) { + this.#unsubscribe(subscriptionEntry); + } + }); + } + + unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) { + this.#subscriptions.forEach((subscriptionEntry) => { + if ( + subscriptionEntry.scope === scope && + subscriptionEntry.origin === origin + ) { + this.#unsubscribe(subscriptionEntry); + } + }); + } + + unsubscribeByOriginAndTabId(origin: string, tabId?: number) { + this.#subscriptions.forEach((subscriptionEntry) => { + if ( + subscriptionEntry.origin === origin && + subscriptionEntry.tabId === tabId + ) { + this.#unsubscribe(subscriptionEntry); + } + }); + } +} diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts new file mode 100644 index 00000000000..d62b2328eba --- /dev/null +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -0,0 +1,101 @@ +import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; +import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; +import { rpcErrors } from '@metamask/rpc-errors'; +import { isObject } from '@metamask/utils'; +import type { + Json, + JsonRpcError, + JsonRpcParams, + JsonRpcRequest, +} from '@metamask/utils'; +import type { + ContentDescriptorObject, + MethodObject, + OpenrpcDocument, +} from '@open-rpc/meta-schema'; +import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; +import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; +import type { Schema, ValidationError } from 'jsonschema'; +import { Validator } from 'jsonschema'; + +const transformError = ( + error: ValidationError, + param: ContentDescriptorObject, + got: unknown, +) => { + // if there is a path, add it to the message + const message = `${ + param.name + (error.path.length > 0 ? `.${error.path.join('.')}` : '') + } ${error.message}`; + + return { + code: -32602, // TODO: could be a different error code or not wrapped in json-rpc error, since this will also be wrapped in a -32602 invalid params error + message, + data: { + param: param.name, + path: error.path, + schema: error.schema, + got, + }, + }; +}; + +const v = new Validator(); + +const dereffedPromise = dereferenceDocument( + MultiChainOpenRPCDocument as unknown as OpenrpcDocument, + makeCustomResolver({}), +); +const multichainMethodCallValidator = async ( + method: string, + params: JsonRpcParams | undefined, +) => { + const dereffed = await dereffedPromise; + const methodToCheck = dereffed.methods.find( + (m) => (m as unknown as ContentDescriptorObject).name === method, + ); + const errors: JsonRpcError[] = []; + // check each param and aggregate errors + (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { + let paramToCheck: Json | undefined; + const p = param as ContentDescriptorObject; + if (isObject(params)) { + paramToCheck = params[p.name]; + } else if (params && Array.isArray(params)) { + paramToCheck = params[i]; + } else { + paramToCheck = undefined; + } + const result = v.validate(paramToCheck, p.schema as unknown as Schema, { + required: p.required, + }); + if (result.errors) { + errors.push( + ...result.errors.map((e) => { + return transformError(e, p, paramToCheck) as JsonRpcError; + }), + ); + } + }); + if (errors.length > 0) { + return errors; + } + // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors + // would be an array and return true if it's empty + return false; +}; + +export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< + JsonRpcRequest, + Json +> = function (request, _response, next, end) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + multichainMethodCallValidator(request.method, request.params).then( + (errors) => { + if (errors) { + return end(rpcErrors.invalidParams({ data: errors })); + } + return next(); + }, + ); +}; diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 55a184b364a..4c8bc65e7fb 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,4 +1,5 @@ -import { validateAndNormalizeScopes } from './authorization'; +import { bucketScopes, validateAndNormalizeScopes } from './authorization'; +import * as Filter from './filter'; import * as Transform from './transform'; import type { ExternalScopeObject } from './types'; import * as Validation from './validation'; @@ -13,6 +14,11 @@ jest.mock('./transform', () => ({ })); const MockTransform = jest.mocked(Transform); +jest.mock('./filter', () => ({ + bucketScopesBySupport: jest.fn(), +})); +const MockFilter = jest.mocked(Filter); + const validScopeObject: ExternalScopeObject = { methods: [], notifications: [], @@ -92,4 +98,129 @@ describe('Scope Authorization', () => { }); }); }); + + describe('bucketScopes', () => { + beforeEach(() => { + let callCount = 0; + MockFilter.bucketScopesBySupport.mockImplementation(() => { + callCount += 1; + return { + supportedScopes: { + 'mock:A': { + methods: [`mock_method_${callCount}`], + notifications: [], + accounts: [], + }, + }, + unsupportedScopes: { + 'mock:B': { + methods: [`mock_method_${callCount}`], + notifications: [], + accounts: [], + }, + }, + }; + }); + }); + + it('buckets the scopes by supported', () => { + const isChainIdSupported = jest.fn(); + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, + }, + { + isChainIdSupported, + isChainIdSupportable: jest.fn(), + }, + ); + + expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( + { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, + }, + { + isChainIdSupported, + }, + ); + }); + + it('buckets the mayble supportable scopes', () => { + const isChainIdSupportable = jest.fn(); + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, + }, + { + isChainIdSupported: jest.fn(), + isChainIdSupportable, + }, + ); + + expect(MockFilter.bucketScopesBySupport).toHaveBeenCalledWith( + { + 'mock:B': { + methods: [`mock_method_1`], + notifications: [], + accounts: [], + }, + }, + { + isChainIdSupported: isChainIdSupportable, + }, + ); + }); + + it('returns the bucketed scopes', () => { + expect( + bucketScopes( + { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, + }, + { + isChainIdSupported: jest.fn(), + isChainIdSupportable: jest.fn(), + }, + ), + ).toStrictEqual({ + supportedScopes: { + 'mock:A': { + methods: [`mock_method_1`], + notifications: [], + accounts: [], + }, + }, + supportableScopes: { + 'mock:A': { + methods: [`mock_method_2`], + notifications: [], + accounts: [], + }, + }, + unsupportableScopes: { + 'mock:B': { + methods: [`mock_method_2`], + notifications: [], + accounts: [], + }, + }, + }); + }); + }); }); diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index c7b98a83570..3dcbef7e40d 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,3 +1,6 @@ +import type { Hex } from '@metamask/utils'; + +import { bucketScopesBySupport } from './filter'; import { normalizeAndMergeScopes } from './transform'; import type { ExternalScopesObject, ScopesObject } from './types'; import { validateScopes } from './validation'; @@ -35,3 +38,32 @@ export const validateAndNormalizeScopes = ( normalizedOptionalScopes, }; }; + +export const bucketScopes = ( + scopes: ScopesObject, + { + isChainIdSupported, + isChainIdSupportable, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + isChainIdSupportable: (chainId: Hex) => boolean; + }, +): { + supportedScopes: ScopesObject; + supportableScopes: ScopesObject; + unsupportableScopes: ScopesObject; +} => { + const { supportedScopes, unsupportedScopes: maybeSupportableScopes } = + bucketScopesBySupport(scopes, { + isChainIdSupported, + }); + + const { + supportedScopes: supportableScopes, + unsupportedScopes: unsupportableScopes, + } = bucketScopesBySupport(maybeSupportableScopes, { + isChainIdSupported: isChainIdSupportable, + }); + + return { supportedScopes, supportableScopes, unsupportableScopes }; +}; diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts new file mode 100644 index 00000000000..c49c7397864 --- /dev/null +++ b/packages/multichain/src/scope/filter.test.ts @@ -0,0 +1,168 @@ +import * as Assert from './assert'; +import { filterScopesSupported, bucketScopesBySupport } from './filter'; + +jest.mock('./assert', () => ({ + assertScopeSupported: jest.fn(), +})); +const MockAssert = jest.mocked(Assert); + +describe('filter', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('filterScopesSupported', () => { + const isChainIdSupported = jest.fn(); + + it('checks if each scope is supported', () => { + filterScopesSupported( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }, + { isChainIdSupported }, + ); + + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:1', + { + methods: ['a'], + notifications: [], + accounts: [], + }, + { isChainIdSupported }, + ); + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:5', + { + methods: ['b'], + notifications: [], + accounts: [], + }, + { isChainIdSupported }, + ); + }); + + it('returns only supported scopes', () => { + MockAssert.assertScopeSupported.mockImplementation((scopeString) => { + if (scopeString === 'eip155:1') { + throw new Error('scope not supported'); + } + }); + + expect( + filterScopesSupported( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }, + { isChainIdSupported }, + ), + ).toStrictEqual({ + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }); + }); + }); + + describe('bucketScopesBySupport', () => { + const isChainIdSupported = jest.fn(); + + it('checks if each scope is supported', () => { + bucketScopesBySupport( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }, + { isChainIdSupported }, + ); + + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:1', + { + methods: ['a'], + notifications: [], + accounts: [], + }, + { isChainIdSupported }, + ); + expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( + 'eip155:5', + { + methods: ['b'], + notifications: [], + accounts: [], + }, + { isChainIdSupported }, + ); + }); + + it('returns supported and unsupported scopes', () => { + MockAssert.assertScopeSupported.mockImplementation((scopeString) => { + if (scopeString === 'eip155:1') { + throw new Error('scope not supported'); + } + }); + + expect( + bucketScopesBySupport( + { + 'eip155:1': { + methods: ['a'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }, + { isChainIdSupported }, + ), + ).toStrictEqual({ + supportedScopes: { + 'eip155:5': { + methods: ['b'], + notifications: [], + accounts: [], + }, + }, + unsupportedScopes: { + 'eip155:1': { + methods: ['a'], + notifications: [], + accounts: [], + }, + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts new file mode 100644 index 00000000000..58157bd6027 --- /dev/null +++ b/packages/multichain/src/scope/filter.ts @@ -0,0 +1,44 @@ +import type { CaipChainId, Hex } from '@metamask/utils'; + +import { assertScopeSupported } from './assert'; +import type { ScopesObject } from './types'; + +export const bucketScopesBySupport = ( + scopes: ScopesObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + const supportedScopes: ScopesObject = {}; + const unsupportedScopes: ScopesObject = {}; + + for (const [scopeString, scopeObject] of Object.entries(scopes)) { + try { + assertScopeSupported(scopeString, scopeObject, { + isChainIdSupported, + }); + supportedScopes[scopeString as CaipChainId] = scopeObject; + } catch (err) { + unsupportedScopes[scopeString as CaipChainId] = scopeObject; + } + } + + return { supportedScopes, unsupportedScopes }; +}; + +export const filterScopesSupported = ( + scopes: ScopesObject, + { + isChainIdSupported, + }: { + isChainIdSupported: (chainId: Hex) => boolean; + }, +) => { + const { supportedScopes } = bucketScopesBySupport(scopes, { + isChainIdSupported, + }); + + return supportedScopes; +}; From 95dfbc9b795520346238bd2f1ebe978c9cf3127a Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:12:56 -0700 Subject: [PATCH 041/146] Revert "remove api related deps" This reverts commit 4ceb11850f8bc7340290940204f3e2a4a4f30db9. --- packages/multichain/package.json | 5 ++ yarn.lock | 123 ++++++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 3 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 313c94a52f6..044b203f0ba 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -51,13 +51,18 @@ "@metamask/controller-utils": "^11.3.0", "@metamask/eth-json-rpc-filters": "^7.0.0", "@metamask/rpc-errors": "^7.0.0", + "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^9.1.0", + "@open-rpc/schema-utils-js": "^2.0.5", + "jsonschema": "^1.2.4", "lodash": "^4.17.21" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", + "@metamask/json-rpc-engine": "^9.0.3", "@metamask/network-controller": "^21.0.1", "@metamask/permission-controller": "^11.0.2", + "@open-rpc/meta-schema": "^1.14.6", "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", "jest": "^27.5.1", diff --git a/yarn.lock b/yarn.lock index b16e5d8f3e4..31ab2d0d9ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1931,6 +1931,48 @@ __metadata: languageName: node linkType: hard +"@json-schema-spec/json-pointer@npm:^0.1.2": + version: 0.1.2 + resolution: "@json-schema-spec/json-pointer@npm:0.1.2" + checksum: 10/2a691ffc11f1a266ca4d0c9e2c99791679d580f343ef69746fad623d1abcf4953adde987890e41f906767d7729604c0182341e9012388b73a44d5b21fb296453 + languageName: node + linkType: hard + +"@json-schema-tools/dereferencer@npm:^1.6.3": + version: 1.6.3 + resolution: "@json-schema-tools/dereferencer@npm:1.6.3" + dependencies: + "@json-schema-tools/reference-resolver": "npm:^1.2.6" + "@json-schema-tools/traverse": "npm:^1.10.4" + fast-safe-stringify: "npm:^2.1.1" + checksum: 10/da6ef5b82a8a9c3a7e62ffcab5c04c581f1e0f8165c0debdb272bb1e08ccd726107ee194487b8fa736cac00fb390b8df74bc1ad1b200eddbe25c98ee0d3d000b + languageName: node + linkType: hard + +"@json-schema-tools/meta-schema@npm:^1.7.5": + version: 1.7.5 + resolution: "@json-schema-tools/meta-schema@npm:1.7.5" + checksum: 10/707dc3a285c26c37d00f418e9d0ef8a2ad1c23d4936ad5aab0ce94c9ae36a7a6125c4ca5048513af64b7e6e527b5472a1701d1f709c379acdd7ad12f6409d2cd + languageName: node + linkType: hard + +"@json-schema-tools/reference-resolver@npm:^1.2.6": + version: 1.2.6 + resolution: "@json-schema-tools/reference-resolver@npm:1.2.6" + dependencies: + "@json-schema-spec/json-pointer": "npm:^0.1.2" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/91d6b4b2ac43f8163fd27bde6d826f29f339e9c7ce3b7e2b73b85e891fa78e3702fd487deda143a0701879cbc2fe28c53a4efce4cd2d2dd2fe6e82b64bbd9c9c + languageName: node + linkType: hard + +"@json-schema-tools/traverse@npm:^1.10.4": + version: 1.10.4 + resolution: "@json-schema-tools/traverse@npm:1.10.4" + checksum: 10/0027bc90df01c5eeee0833e722b7320b53be8b5ce3f4e0e4a6e45713a38e6f88f21aba31e3dd973093ef75cd21a40c07fe8f112da8f49a7919b1c0e44c904d20 + languageName: node + linkType: hard + "@keystonehq/alias-sampling@npm:^0.1.1": version: 0.1.2 resolution: "@keystonehq/alias-sampling@npm:0.1.2" @@ -3060,13 +3102,18 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/controller-utils": "npm:^11.3.0" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" + "@metamask/json-rpc-engine": "npm:^9.0.3" "@metamask/network-controller": "npm:^21.0.1" "@metamask/permission-controller": "npm:^11.0.2" "@metamask/rpc-errors": "npm:^7.0.0" + "@metamask/safe-event-emitter": "npm:^3.0.0" "@metamask/utils": "npm:^9.1.0" + "@open-rpc/meta-schema": "npm:^1.14.6" + "@open-rpc/schema-utils-js": "npm:^2.0.5" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" + jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" @@ -4028,6 +4075,31 @@ __metadata: languageName: node linkType: hard +"@open-rpc/meta-schema@npm:^1.14.6, @open-rpc/meta-schema@npm:^1.14.9": + version: 1.14.9 + resolution: "@open-rpc/meta-schema@npm:1.14.9" + checksum: 10/51505dcf7aa1a2285c78953c9b33711cede5f2765aa37dcb9ee7756d689e2ff2a89cfc6039504f0569c52a805fb9aa18f30a7c02ad7a06e793c801e43b419104 + languageName: node + linkType: hard + +"@open-rpc/schema-utils-js@npm:^2.0.5": + version: 2.0.5 + resolution: "@open-rpc/schema-utils-js@npm:2.0.5" + dependencies: + "@json-schema-tools/dereferencer": "npm:^1.6.3" + "@json-schema-tools/meta-schema": "npm:^1.7.5" + "@json-schema-tools/reference-resolver": "npm:^1.2.6" + "@open-rpc/meta-schema": "npm:^1.14.9" + ajv: "npm:^6.10.0" + detect-node: "npm:^2.0.4" + fast-safe-stringify: "npm:^2.0.7" + fs-extra: "npm:^10.1.0" + is-url: "npm:^1.2.4" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/9e10215606e9a00a47b082c9cfd70d05bf0d38de6cf1c147246c545c6997375d94cd3caafe919b71178df58b5facadfd0dcc8b6857bf5e79c40e5e33683dd3d5 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -4968,7 +5040,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4": +"ajv@npm:^6.10.0, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -6364,6 +6436,13 @@ __metadata: languageName: node linkType: hard +"detect-node@npm:^2.0.4": + version: 2.1.0 + resolution: "detect-node@npm:2.1.0" + checksum: 10/832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e + languageName: node + linkType: hard + "diff-sequences@npm:^27.5.1": version: 27.5.1 resolution: "diff-sequences@npm:27.5.1" @@ -7372,7 +7451,7 @@ __metadata: languageName: node linkType: hard -"fast-safe-stringify@npm:^2.0.6": +"fast-safe-stringify@npm:^2.0.6, fast-safe-stringify@npm:^2.0.7, fast-safe-stringify@npm:^2.1.1": version: 2.1.1 resolution: "fast-safe-stringify@npm:2.1.1" checksum: 10/dc1f063c2c6ac9533aee14d406441f86783a8984b2ca09b19c2fe281f9ff59d315298bc7bc22fd1f83d26fe19ef2f20e2ddb68e96b15040292e555c5ced0c1e4 @@ -7612,6 +7691,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^10.1.0": + version: 10.1.0 + resolution: "fs-extra@npm:10.1.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10/05ce2c3b59049bcb7b52001acd000e44b3c4af4ec1f8839f383ef41ec0048e3cfa7fd8a637b1bddfefad319145db89be91f4b7c1db2908205d38bf91e7d1d3b7 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -7905,7 +7995,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -8581,6 +8671,13 @@ __metadata: languageName: node linkType: hard +"is-url@npm:^1.2.4": + version: 1.2.4 + resolution: "is-url@npm:1.2.4" + checksum: 10/100e74b3b1feab87a43ef7653736e88d997eb7bd32e71fd3ebc413e58c1cbe56269699c776aaea84244b0567f2a7d68dfaa512a062293ed2f9fdecb394148432 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -9517,6 +9614,19 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10/03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 + languageName: node + linkType: hard + "jsonschema@npm:^1.2.4": version: 1.4.1 resolution: "jsonschema@npm:1.4.1" @@ -12344,6 +12454,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^2.0.0": + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 10/ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" From 9bcf86965d48a8499bdfe12d279e3dbc1edeb4f2 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:18:08 -0700 Subject: [PATCH 042/146] Fix package.json --- packages/multichain/package.json | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 8bb21596986..4fa4f7ccfc0 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -18,14 +18,19 @@ "sideEffects": false, "exports": { ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.js", - "types": "./dist/types/index.d.ts" + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } }, "./package.json": "./package.json" }, - "main": "./dist/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", "files": [ "dist/" ], @@ -35,10 +40,11 @@ "changelog:update": "../../scripts/update-changelog.sh @metamask/multichain", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/multichain", "publish:preview": "yarn npm publish --tag preview", - "test": "jest --reporters=jest-silent-reporter", - "test:clean": "jest --clearCache", - "test:verbose": "jest --verbose", - "test:watch": "jest --watch" + "since-latest-release": "../../scripts/since-latest-release.sh", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", + "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", + "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", From afb2e2c0d8c0facca91b693444135641ef693d03 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:34:09 -0700 Subject: [PATCH 043/146] fix bad merge --- packages/multichain/src/index.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 47a6b90661f..03bbb442622 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -1,4 +1,3 @@ -<<<<<<< HEAD export { getEthAccounts, setEthAccounts, @@ -11,9 +10,7 @@ export { } from './adapters/caip-permission-adapter-permittedChains'; export type { Caip25Authorization } from './scope/authorization'; -export { - validateAndNormalizeScopes, -} from './scope/authorization'; +export { validateAndNormalizeScopes } from './scope/authorization'; export * from './scope/types'; export { isSupportedScopeString, @@ -38,15 +35,3 @@ export { Caip25CaveatMutatorFactories, removeScope, } from './caip25Permission'; -||||||| 8fb04fc2 -======= -/** - * Example function that returns a greeting for the given name. - * - * @param name - The name to greet. - * @returns The greeting. - */ -export default function greeter(name: string): string { - return `Hello, ${name}!`; -} ->>>>>>> initialize-caip-multichain From 7c97afe00a77879aa5dcf01089180045635e8dde Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:37:57 -0700 Subject: [PATCH 044/146] fix bad merge --- packages/multichain/src/index.ts | 13 ------------- .../middlewares/multichainMethodCallValidator.ts | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index f46f4c97c74..f764ea5b3ec 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -1,4 +1,3 @@ -<<<<<<< HEAD export { getEthAccounts, setEthAccounts, @@ -49,15 +48,3 @@ export { Caip25CaveatMutatorFactories, removeScope, } from './caip25Permission'; -||||||| 8fb04fc2 -======= -/** - * Example function that returns a greeting for the given name. - * - * @param name - The name to greet. - * @returns The greeting. - */ -export default function greeter(name: string): string { - return `Hello, ${name}!`; -} ->>>>>>> initialize-caip-multichain diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index d62b2328eba..cc075140e28 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -24,8 +24,8 @@ const transformError = ( got: unknown, ) => { // if there is a path, add it to the message - const message = `${ - param.name + (error.path.length > 0 ? `.${error.path.join('.')}` : '') + const message = `${param.name}${ + error.path.length > 0 ? `.${error.path.join('.')}` : '' } ${error.message}`; return { From 109a7bf5a25ef4f9b15a3ffe081cacac286d0114 Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 17 Oct 2024 14:21:11 -0700 Subject: [PATCH 045/146] Update packages/controller-utils/src/util.test.ts Co-authored-by: Mark Stacey --- packages/controller-utils/src/util.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/controller-utils/src/util.test.ts b/packages/controller-utils/src/util.test.ts index 3126fb7ef12..a28cc2df18e 100644 --- a/packages/controller-utils/src/util.test.ts +++ b/packages/controller-utils/src/util.test.ts @@ -614,6 +614,10 @@ describe('util', () => { describe('isEqualCaseInsensitive', () => { it('returns false for non-string values', () => { + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(null, null)).toBe(false); + // @ts-expect-error Invalid type for testing purposes + expect(util.isEqualCaseInsensitive(5, 5)).toBe(false); // @ts-expect-error Invalid type for testing purposes expect(util.isEqualCaseInsensitive(null, 'test')).toBe(false); // @ts-expect-error Invalid type for testing purposes From dae4f73d4e54c88a492112977146f99d20365e4c Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 17 Oct 2024 15:48:26 -0700 Subject: [PATCH 046/146] add account support check in validator (#4816) ## Explanation Mirrors the [wallet_createSession handler ](https://github.com/MetaMask/metamask-extension/pull/27782/files#diff-107459889087f2776c6db636bd45498bef6749302f9d2dc633b4de17fede40a3R96-R108) in how eth account support is checked/asserted. Opted to do this rather than modify `assertScopeSupported` because the `bucketScopes` helper also relies on `assertScopedSupported` but doesn't care about accounts (which is why eth accounts are checked outside of assertScopeSupported in the wallet_createSession handler currently) ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --------- Co-authored-by: Alex Donesky --- .../multichain/src/caip25Permission.test.ts | 71 ++++++++++++++++++- packages/multichain/src/caip25Permission.ts | 22 ++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index 818035ff8a5..900b89c907c 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -44,6 +44,7 @@ describe('endowment:caip25', () => { const specification = caip25EndowmentBuilder.specificationBuilder({ methodHooks: { findNetworkClientIdByChainId: jest.fn(), + listAccounts: jest.fn(), }, }); expect(specification).toStrictEqual({ @@ -227,9 +228,11 @@ describe('endowment:caip25', () => { describe('permission validator', () => { const findNetworkClientIdByChainId = jest.fn(); + const listAccounts = jest.fn(); const { validator } = caip25EndowmentBuilder.specificationBuilder({ methodHooks: { findNetworkClientIdByChainId, + listAccounts, }, }); @@ -493,7 +496,7 @@ describe('endowment:caip25', () => { }, }, normalizedOptionalScopes: { - 'eip155:1': { + 'eip155:5': { methods: ['normalized_optional'], notifications: [], accounts: [], @@ -534,7 +537,7 @@ describe('endowment:caip25', () => { } expect(MockScopeAssert.assertScopesSupported).toHaveBeenCalledWith( { - 'eip155:1': { + 'eip155:5': { methods: ['normalized_optional'], notifications: [], accounts: [], @@ -549,6 +552,61 @@ describe('endowment:caip25', () => { expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); + it('throws if the eth accounts specified in the normalized scopeObjects are not found in the wallet keyring', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + normalizedOptionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + }); + listAccounts.mockReturnValue([{ address: '0xdead' }]); // missing '0xbeef' + + expect(() => { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + }).toThrow( + new Error( + `${Caip25EndowmentPermissionName} error: Received eip155 account value(s) for caveat of type "${Caip25CaveatType}" that were not found in the wallet keyring.`, + ), + ); + }); + it('throws if the input requiredScopes does not match the output of validateAndNormalizeScopes', () => { MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ normalizedRequiredScopes: {}, @@ -560,6 +618,8 @@ describe('endowment:caip25', () => { }, }, }); + listAccounts.mockReturnValue([{ address: '0xbeef' }]); + expect(() => { validator({ caveats: [ @@ -603,6 +663,8 @@ describe('endowment:caip25', () => { }, normalizedOptionalScopes: {}, }); + listAccounts.mockReturnValue([{ address: '0xdead' }]); + expect(() => { validator({ caveats: [ @@ -652,6 +714,11 @@ describe('endowment:caip25', () => { }, }, }); + listAccounts.mockReturnValue([ + { address: '0xdead' }, + { address: '0xbeef' }, + ]); + expect( validator({ caveats: [ diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index f4f7ec88c18..e58355c1f4e 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -19,6 +19,7 @@ import { import { strict as assert } from 'assert'; import { cloneDeep, isEqual } from 'lodash'; +import { getEthAccounts } from './adapters/caip-permission-adapter-eth-accounts'; import { assertScopesSupported } from './scope/assert'; import { validateAndNormalizeScopes } from './scope/authorization'; import type { @@ -56,6 +57,7 @@ type Caip25EndowmentSpecification = ValidPermissionSpecification<{ type Caip25EndowmentSpecificationBuilderOptions = { methodHooks: { findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId; + listAccounts: () => { address: Hex }[]; }; }; @@ -120,6 +122,26 @@ const specificationBuilder: PermissionSpecificationBuilder< isChainIdSupported, }); + // Fetch EVM accounts from native wallet keyring + // These addresses are lowercased already + const existingEvmAddresses = methodHooks + .listAccounts() + .map((account) => account.address); + const ethAccounts = getEthAccounts({ + requiredScopes: normalizedRequiredScopes, + optionalScopes: normalizedOptionalScopes, + isMultichainOrigin, + }).map((address) => address.toLowerCase() as Hex); + + const allEthAccountsSupported = ethAccounts.every((address) => + existingEvmAddresses.includes(address), + ); + if (!allEthAccountsSupported) { + throw new Error( + `${Caip25EndowmentPermissionName} error: Received eip155 account value(s) for caveat of type "${Caip25CaveatType}" that were not found in the wallet keyring.`, + ); + } + assert.deepEqual(requiredScopes, normalizedRequiredScopes); assert.deepEqual(optionalScopes, normalizedOptionalScopes); }, From fad338dc1c9dd3c575673c7e7c8040bbd8dae074 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 08:49:52 -0700 Subject: [PATCH 047/146] remove caip-permission-adapter-middleware --- ...caip-permission-adapter-middleware.test.ts | 148 ------------------ .../caip-permission-adapter-middleware.ts | 80 ---------- 2 files changed, 228 deletions(-) delete mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts delete mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.ts diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts deleted file mode 100644 index c044c73b0f0..00000000000 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { providerErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; - -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { caipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; - -const baseRequest = { - id: 1, - jsonrpc: '2.0' as const, - origin: 'http://test.com', - networkClientId: 'mainnet', - method: 'eth_call', - params: { - foo: 'bar', - }, -}; - -const createMockedHandler = () => { - const next = jest.fn(); - const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ - value: { - requiredScopes: { - 'eip155:1': { - methods: ['eth_call'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], - accounts: [], - }, - }, - optionalScopes: { - 'eip155:1': { - methods: ['net_version'], - notifications: [], - accounts: [], - }, - wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - unhandled: { - methods: ['foobar'], - notifications: [], - accounts: [], - }, - }, - isMultichainOrigin: true, - }, - }); - const getNetworkConfigurationByNetworkClientId = jest - .fn() - .mockImplementation((networkClientId: string) => { - const chainId = - { - mainnet: '0x1', - goerli: '0x5', - }[networkClientId] || '0x999'; - return { - chainId, - }; - }); - const handler = ( - request: JsonRpcRequest & { - networkClientId: string; - origin: string; - }, - ) => - caipPermissionAdapterMiddleware(request, {}, next, end, { - getCaveat, - getNetworkConfigurationByNetworkClientId, - }); - - return { - next, - end, - getCaveat, - getNetworkConfigurationByNetworkClientId, - handler, - }; -}; - -describe('CaipPermissionAdapterMiddleware', () => { - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const { handler, getCaveat } = createMockedHandler(); - await handler(baseRequest); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - }); - - it('allows the request when there is no CAIP-25 endowment permission', async () => { - const { handler, getCaveat, next } = createMockedHandler(); - getCaveat.mockImplementation(() => { - throw new Error('permission not found'); - }); - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - - it('allows the request when the CAIP-25 endowment permission was not granted from the multichain API', async () => { - const { handler, getCaveat, next } = createMockedHandler(); - getCaveat.mockReturnValue({ - value: { - isMultichainOrigin: false, - }, - }); - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - - it('gets the chainId for the request networkClientId', async () => { - const { handler, getNetworkConfigurationByNetworkClientId } = - createMockedHandler(); - await handler(baseRequest); - expect(getNetworkConfigurationByNetworkClientId).toHaveBeenCalledWith( - 'mainnet', - ); - }); - - describe('when the CAIP-25 endowment permission was granted over the multichain API', () => { - it('throws an error if the requested method is not authorized for the scope specified in the request', async () => { - const { handler, end } = createMockedHandler(); - - await handler({ - ...baseRequest, - method: 'unauthorized_method', - }); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('allows the request if the requested scope method is authorized in the current scope', async () => { - const { handler, next } = createMockedHandler(); - - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts deleted file mode 100644 index 865a4cccfcb..00000000000 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { - NetworkConfiguration, - NetworkClientId, -} from '@metamask/network-controller'; -import type { Caveat } from '@metamask/permission-controller'; -import { providerErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; - -import type { Caip25CaveatValue } from '../caip25Permission'; -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import { KnownWalletScopeString, type ScopeString } from '../scope/types'; - -/** - * Middleware to handle CAIP-25 permission requests. - * - * @param request - The request object. - * @param _response - The response object. - * @param next - The next middleware function. - * @param end - The end function. - * @param hooks - The hooks object. - * @param hooks.getCaveat - Function to retrieve a caveat. - * @param hooks.getNetworkConfigurationByNetworkClientId - Function to retrieve a network configuration. - */ -export async function caipPermissionAdapterMiddleware( - request: JsonRpcRequest & { - networkClientId: NetworkClientId; - origin: string; - }, - _response: unknown, - next: () => Promise, - end: (error?: Error) => void, - hooks: { - getCaveat: ( - ...args: unknown[] - ) => Caveat; - getNetworkConfigurationByNetworkClientId: ( - networkClientId: NetworkClientId, - ) => NetworkConfiguration; - }, -) { - const { networkClientId, method } = request; - - let caveat; - try { - caveat = hooks.getCaveat( - request.origin, - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - } catch (err) { - // noop - } - if (!caveat?.value?.isMultichainOrigin) { - return next(); - } - - const { chainId } = - hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - - const scope: ScopeString = `eip155:${parseInt(chainId, 16)}`; - - const scopesObject = mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - ); - - if ( - !scopesObject[scope]?.methods?.includes(method) && - !scopesObject[KnownWalletScopeString.Eip155]?.methods?.includes(method) && - !scopesObject.wallet?.methods?.includes(method) - ) { - return end(providerErrors.unauthorized()); - } - - return next(); -} From 8208931de69ae4ccf964257702a6b6a26a4b2e3d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 08:50:09 -0700 Subject: [PATCH 048/146] Revert "remove caip-permission-adapter-middleware" This reverts commit fad338dc1c9dd3c575673c7e7c8040bbd8dae074. --- ...caip-permission-adapter-middleware.test.ts | 148 ++++++++++++++++++ .../caip-permission-adapter-middleware.ts | 80 ++++++++++ 2 files changed, 228 insertions(+) create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.ts diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts new file mode 100644 index 00000000000..c044c73b0f0 --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts @@ -0,0 +1,148 @@ +import { providerErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { caipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; + +const baseRequest = { + id: 1, + jsonrpc: '2.0' as const, + origin: 'http://test.com', + networkClientId: 'mainnet', + method: 'eth_call', + params: { + foo: 'bar', + }, +}; + +const createMockedHandler = () => { + const next = jest.fn(); + const end = jest.fn(); + const getCaveat = jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_call'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + }, + optionalScopes: { + 'eip155:1': { + methods: ['net_version'], + notifications: [], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + unhandled: { + methods: ['foobar'], + notifications: [], + accounts: [], + }, + }, + isMultichainOrigin: true, + }, + }); + const getNetworkConfigurationByNetworkClientId = jest + .fn() + .mockImplementation((networkClientId: string) => { + const chainId = + { + mainnet: '0x1', + goerli: '0x5', + }[networkClientId] || '0x999'; + return { + chainId, + }; + }); + const handler = ( + request: JsonRpcRequest & { + networkClientId: string; + origin: string; + }, + ) => + caipPermissionAdapterMiddleware(request, {}, next, end, { + getCaveat, + getNetworkConfigurationByNetworkClientId, + }); + + return { + next, + end, + getCaveat, + getNetworkConfigurationByNetworkClientId, + handler, + }; +}; + +describe('CaipPermissionAdapterMiddleware', () => { + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { + const { handler, getCaveat } = createMockedHandler(); + await handler(baseRequest); + expect(getCaveat).toHaveBeenCalledWith( + 'http://test.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + }); + + it('allows the request when there is no CAIP-25 endowment permission', async () => { + const { handler, getCaveat, next } = createMockedHandler(); + getCaveat.mockImplementation(() => { + throw new Error('permission not found'); + }); + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + + it('allows the request when the CAIP-25 endowment permission was not granted from the multichain API', async () => { + const { handler, getCaveat, next } = createMockedHandler(); + getCaveat.mockReturnValue({ + value: { + isMultichainOrigin: false, + }, + }); + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + + it('gets the chainId for the request networkClientId', async () => { + const { handler, getNetworkConfigurationByNetworkClientId } = + createMockedHandler(); + await handler(baseRequest); + expect(getNetworkConfigurationByNetworkClientId).toHaveBeenCalledWith( + 'mainnet', + ); + }); + + describe('when the CAIP-25 endowment permission was granted over the multichain API', () => { + it('throws an error if the requested method is not authorized for the scope specified in the request', async () => { + const { handler, end } = createMockedHandler(); + + await handler({ + ...baseRequest, + method: 'unauthorized_method', + }); + expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); + }); + + it('allows the request if the requested scope method is authorized in the current scope', async () => { + const { handler, next } = createMockedHandler(); + + await handler(baseRequest); + expect(next).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts new file mode 100644 index 00000000000..865a4cccfcb --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -0,0 +1,80 @@ +import type { + NetworkConfiguration, + NetworkClientId, +} from '@metamask/network-controller'; +import type { Caveat } from '@metamask/permission-controller'; +import { providerErrors } from '@metamask/rpc-errors'; +import type { JsonRpcRequest } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import { + Caip25CaveatType, + Caip25EndowmentPermissionName, +} from '../caip25Permission'; +import { mergeScopes } from '../scope/transform'; +import { KnownWalletScopeString, type ScopeString } from '../scope/types'; + +/** + * Middleware to handle CAIP-25 permission requests. + * + * @param request - The request object. + * @param _response - The response object. + * @param next - The next middleware function. + * @param end - The end function. + * @param hooks - The hooks object. + * @param hooks.getCaveat - Function to retrieve a caveat. + * @param hooks.getNetworkConfigurationByNetworkClientId - Function to retrieve a network configuration. + */ +export async function caipPermissionAdapterMiddleware( + request: JsonRpcRequest & { + networkClientId: NetworkClientId; + origin: string; + }, + _response: unknown, + next: () => Promise, + end: (error?: Error) => void, + hooks: { + getCaveat: ( + ...args: unknown[] + ) => Caveat; + getNetworkConfigurationByNetworkClientId: ( + networkClientId: NetworkClientId, + ) => NetworkConfiguration; + }, +) { + const { networkClientId, method } = request; + + let caveat; + try { + caveat = hooks.getCaveat( + request.origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch (err) { + // noop + } + if (!caveat?.value?.isMultichainOrigin) { + return next(); + } + + const { chainId } = + hooks.getNetworkConfigurationByNetworkClientId(networkClientId); + + const scope: ScopeString = `eip155:${parseInt(chainId, 16)}`; + + const scopesObject = mergeScopes( + caveat.value.requiredScopes, + caveat.value.optionalScopes, + ); + + if ( + !scopesObject[scope]?.methods?.includes(method) && + !scopesObject[KnownWalletScopeString.Eip155]?.methods?.includes(method) && + !scopesObject.wallet?.methods?.includes(method) + ) { + return end(providerErrors.unauthorized()); + } + + return next(); +} From c5980c62e07251cb62abde2849f48ee2908cabc3 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 08:51:58 -0700 Subject: [PATCH 049/146] remove caip-permission-adapter-middleware from exports --- packages/multichain/src/index.test.ts | 1 - packages/multichain/src/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 7cf4f393210..664c35f6ea0 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -6,7 +6,6 @@ describe('@metamask/multichain', () => { Array [ "getEthAccounts", "setEthAccounts", - "caipPermissionAdapterMiddleware", "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 03bbb442622..6c4d641f554 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -2,7 +2,6 @@ export { getEthAccounts, setEthAccounts, } from './adapters/caip-permission-adapter-eth-accounts'; -export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; export { getPermittedEthChainIds, addPermittedEthChainId, From 5c6bb8f5ce2e76991ee772b8b43073d299e0b088 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 08:52:14 -0700 Subject: [PATCH 050/146] Revert "remove caip-permission-adapter-middleware from exports" This reverts commit c5980c62e07251cb62abde2849f48ee2908cabc3. --- packages/multichain/src/index.test.ts | 1 + packages/multichain/src/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index ff29ce8f43a..d06cd6094eb 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -6,6 +6,7 @@ describe('@metamask/multichain', () => { Array [ "getEthAccounts", "setEthAccounts", + "caipPermissionAdapterMiddleware", "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index c203b78cfcf..f764ea5b3ec 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -2,6 +2,7 @@ export { getEthAccounts, setEthAccounts, } from './adapters/caip-permission-adapter-eth-accounts'; +export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; export { getPermittedEthChainIds, addPermittedEthChainId, From a7a8e6e4db0ccbd97124e201f5e0a49136354c5c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 09:06:56 -0700 Subject: [PATCH 051/146] remove types/@metamask/eth-json-rpc-filters.d.ts --- types/@metamask/eth-json-rpc-filters.d.ts | 1 - 1 file changed, 1 deletion(-) delete mode 100644 types/@metamask/eth-json-rpc-filters.d.ts diff --git a/types/@metamask/eth-json-rpc-filters.d.ts b/types/@metamask/eth-json-rpc-filters.d.ts deleted file mode 100644 index 5a51785b82b..00000000000 --- a/types/@metamask/eth-json-rpc-filters.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@metamask/eth-json-rpc-filters/subscriptionManager'; From 54829e006408c1758be0b67f3c5055ba6a7f7c0d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 09:07:14 -0700 Subject: [PATCH 052/146] Revert "remove types/@metamask/eth-json-rpc-filters.d.ts" This reverts commit a7a8e6e4db0ccbd97124e201f5e0a49136354c5c. --- types/@metamask/eth-json-rpc-filters.d.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 types/@metamask/eth-json-rpc-filters.d.ts diff --git a/types/@metamask/eth-json-rpc-filters.d.ts b/types/@metamask/eth-json-rpc-filters.d.ts new file mode 100644 index 00000000000..5a51785b82b --- /dev/null +++ b/types/@metamask/eth-json-rpc-filters.d.ts @@ -0,0 +1 @@ +declare module '@metamask/eth-json-rpc-filters/subscriptionManager'; From 42297f964fdb1623bc9da75e377c5ed9c662cd3f Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 21 Oct 2024 14:22:58 -0500 Subject: [PATCH 053/146] add back readme content --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d13cf342474..d01734fa5b7 100644 --- a/README.md +++ b/README.md @@ -122,11 +122,15 @@ linkStyle default opacity:0.5 logging_controller --> controller_utils; message_manager --> base_controller; message_manager --> controller_utils; + multichain --> controller_utils; + multichain --> network_controller; + multichain --> permission_controller; name_controller --> base_controller; name_controller --> controller_utils; network_controller --> base_controller; network_controller --> controller_utils; network_controller --> eth_json_rpc_provider; + network_controller --> json_rpc_engine; notification_controller --> base_controller; notification_services_controller --> base_controller; notification_services_controller --> controller_utils; @@ -134,6 +138,7 @@ linkStyle default opacity:0.5 notification_services_controller --> profile_sync_controller; permission_controller --> base_controller; permission_controller --> controller_utils; + permission_controller --> json_rpc_engine; permission_controller --> approval_controller; permission_log_controller --> base_controller; permission_log_controller --> json_rpc_engine; @@ -151,6 +156,7 @@ linkStyle default opacity:0.5 profile_sync_controller --> network_controller; queued_request_controller --> base_controller; queued_request_controller --> controller_utils; + queued_request_controller --> json_rpc_engine; queued_request_controller --> network_controller; queued_request_controller --> selected_network_controller; rate_limit_controller --> base_controller; From 56176d172c4b9d58ae923d95e6afd29fce149cf9 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 21 Oct 2024 15:01:33 -0700 Subject: [PATCH 054/146] yarn lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 83909d3835c..9277381a565 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2925,7 +2925,7 @@ __metadata: languageName: node linkType: hard -"@metamask/json-rpc-engine@npm:^9.0.1, @metamask/json-rpc-engine@npm:^9.0.2": +"@metamask/json-rpc-engine@npm:^9.0.1, @metamask/json-rpc-engine@npm:^9.0.2, @metamask/json-rpc-engine@npm:^9.0.3": version: 9.0.3 resolution: "@metamask/json-rpc-engine@npm:9.0.3" dependencies: From 72033583c9b3168993306b51ae03221666944082 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 22 Oct 2024 09:49:49 -0700 Subject: [PATCH 055/146] bump network-controller dep --- packages/multichain/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 313c94a52f6..c06fe393968 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -56,7 +56,7 @@ }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", - "@metamask/network-controller": "^21.0.1", + "@metamask/network-controller": "^21.1.0", "@metamask/permission-controller": "^11.0.2", "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", diff --git a/yarn.lock b/yarn.lock index dee08170497..893ed6048b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3037,7 +3037,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/controller-utils": "npm:^11.3.0" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" - "@metamask/network-controller": "npm:^21.0.1" + "@metamask/network-controller": "npm:^21.1.0" "@metamask/permission-controller": "npm:^11.0.2" "@metamask/rpc-errors": "npm:^7.0.0" "@metamask/utils": "npm:^9.1.0" @@ -3074,7 +3074,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/network-controller@npm:^21.0.1, @metamask/network-controller@npm:^21.1.0, @metamask/network-controller@workspace:packages/network-controller": +"@metamask/network-controller@npm:^21.1.0, @metamask/network-controller@workspace:packages/network-controller": version: 0.0.0-use.local resolution: "@metamask/network-controller@workspace:packages/network-controller" dependencies: From 046133a766b36ea9fb5da499b8899cbd3deccf0d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 22 Oct 2024 09:50:46 -0700 Subject: [PATCH 056/146] add Scoped Properties to Caip25Authorization type --- .../multichain/src/scope/authorization.ts | 21 ++++++++++++------- packages/multichain/src/scope/types.ts | 16 +++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index c7b98a83570..2b97a231e10 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,19 +1,26 @@ +import type { Json } from '@metamask/utils'; + import { normalizeAndMergeScopes } from './transform'; -import type { ExternalScopesObject, ScopesObject } from './types'; +import type { + ExternalScopesObject, + ExternalScopeString, + ScopesObject, +} from './types'; import { validateScopes } from './validation'; -export type Caip25Authorization = +export type Caip25Authorization = ( | { requiredScopes: ExternalScopesObject; optionalScopes?: ExternalScopesObject; - sessionProperties?: Record; } - | ({ + | { requiredScopes?: ExternalScopesObject; optionalScopes: ExternalScopesObject; - } & { - sessionProperties?: Record; - }); + } +) & { + sessionProperties?: Record; + scopedProperties?: Record; +}; export const validateAndNormalizeScopes = ( requiredScopes: ExternalScopesObject, diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index 0d5c87fbb13..ddd4695628e 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -1,15 +1,16 @@ import MetaMaskOpenRPCDocument from '@metamask/api-specs'; +import { + isCaipNamespace, + isCaipChainId, + parseCaipChainId, +} from '@metamask/utils'; import type { CaipChainId, CaipReference, CaipAccountId, KnownCaipNamespace, CaipNamespace, -} from '@metamask/utils'; -import { - isCaipNamespace, - isCaipChainId, - parseCaipChainId, + Json, } from '@metamask/utils'; export enum KnownWalletScopeString { @@ -97,7 +98,4 @@ export const parseScopeString = ( return {}; }; -export type ScopedProperties = Record< - ExternalScopeString, - Record ->; +export type ScopedProperties = Record>; From 67b222e3ba7f436cb10d788fb32a177facb98387 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 22 Oct 2024 11:07:01 -0700 Subject: [PATCH 057/146] Fix ScopedProperties type --- packages/multichain/src/scope/types.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index ddd4695628e..bc15442ed40 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -98,4 +98,6 @@ export const parseScopeString = ( return {}; }; -export type ScopedProperties = Record>; +export type ScopedProperties = Record> & { + [KnownCaipNamespace.Wallet]?: Record; +}; From 009fb4aa59f7d92cefe386018aec307e765a2026 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 22 Oct 2024 13:00:30 -0700 Subject: [PATCH 058/146] Loosen get adapter param types (#4835) ## Explanation Loosen `getEthAccounts` and `getPermittedEthChainIds` param type ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- .../adapters/caip-permission-adapter-eth-accounts.test.ts | 1 - .../src/adapters/caip-permission-adapter-eth-accounts.ts | 7 ++++++- .../caip-permission-adapter-permittedChains.test.ts | 1 - .../adapters/caip-permission-adapter-permittedChains.ts | 5 ++++- packages/multichain/src/caip25Permission.ts | 1 - 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index eb559666787..6f043ed763b 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -49,7 +49,6 @@ describe('CAIP-25 eth_accounts adapters', () => { accounts: ['wallet:eip155:0x5'], }, }, - isMultichainOrigin: false, }); expect(ethAccounts).toStrictEqual([ diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts index 6c72f1d07ba..87848250b52 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.ts @@ -19,7 +19,12 @@ const isEip155ScopeString = (scopeString: ScopeString) => { ); }; -export const getEthAccounts = (caip25CaveatValue: Caip25CaveatValue) => { +export const getEthAccounts = ( + caip25CaveatValue: Pick< + Caip25CaveatValue, + 'requiredScopes' | 'optionalScopes' + >, +) => { const ethAccounts: string[] = []; const sessionScopes = mergeScopes( caip25CaveatValue.requiredScopes, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 4020c2442bf..6f6fdc78d49 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -46,7 +46,6 @@ describe('CAIP-25 permittedChains adapters', () => { accounts: ['eip155:100:0x100'], }, }, - isMultichainOrigin: false, }); expect(ethChainIds).toStrictEqual(['0x1', '0x5', '0xa', '0x64']); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 6a59efa916f..0528a14ea77 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -13,7 +13,10 @@ import { } from '../scope/types'; export const getPermittedEthChainIds = ( - caip25CaveatValue: Caip25CaveatValue, + caip25CaveatValue: Pick< + Caip25CaveatValue, + 'requiredScopes' | 'optionalScopes' + >, ) => { const ethChainIds: Hex[] = []; const sessionScopes = mergeScopes( diff --git a/packages/multichain/src/caip25Permission.ts b/packages/multichain/src/caip25Permission.ts index e58355c1f4e..5914f1687a8 100644 --- a/packages/multichain/src/caip25Permission.ts +++ b/packages/multichain/src/caip25Permission.ts @@ -130,7 +130,6 @@ const specificationBuilder: PermissionSpecificationBuilder< const ethAccounts = getEthAccounts({ requiredScopes: normalizedRequiredScopes, optionalScopes: normalizedOptionalScopes, - isMultichainOrigin, }).map((address) => address.toLowerCase() as Hex); const allEthAccountsSupported = ethAccounts.every((address) => From 0631c487e9f16efb966f7c969d861143031133af Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 08:53:57 -0700 Subject: [PATCH 059/146] Seperate types and constants --- ...permission-adapter-permittedChains.test.ts | 2 +- ...caip-permission-adapter-permittedChains.ts | 8 +-- packages/multichain/src/index.test.ts | 12 ++--- packages/multichain/src/index.ts | 18 ++++++- packages/multichain/src/scope/constants.ts | 47 ++++++++++++++++ .../multichain/src/scope/supported.test.ts | 12 ++--- packages/multichain/src/scope/supported.ts | 6 +-- packages/multichain/src/scope/types.ts | 54 +++++-------------- 8 files changed, 96 insertions(+), 63 deletions(-) create mode 100644 packages/multichain/src/scope/constants.ts diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 6f6fdc78d49..1d55cf6f607 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -1,5 +1,5 @@ import type { Caip25CaveatValue } from '../caip25Permission'; -import { KnownNotifications, KnownRpcMethods } from '../scope/types'; +import { KnownNotifications, KnownRpcMethods } from '../scope/constants'; import { addPermittedEthChainId, getPermittedEthChainIds, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index 0528a14ea77..f9944189468 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -3,14 +3,10 @@ import type { Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; +import { KnownNotifications, KnownRpcMethods } from '../scope/constants'; import { getUniqueArrayItems, mergeScopes } from '../scope/transform'; import type { ScopesObject, ScopeString } from '../scope/types'; -import { - KnownNotifications, - KnownRpcMethods, - KnownWalletScopeString, - parseScopeString, -} from '../scope/types'; +import { KnownWalletScopeString, parseScopeString } from '../scope/types'; export const getPermittedEthChainIds = ( caip25CaveatValue: Pick< diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 664c35f6ea0..7b61fec8afa 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -10,6 +10,12 @@ describe('@metamask/multichain', () => { "addPermittedEthChainId", "setPermittedEthChainIds", "validateAndNormalizeScopes", + "KnownWalletRpcMethods", + "KnownRpcMethods", + "KnownWalletNamespaceRpcMethods", + "KnownNotifications", + "parseScopeString", + "KnownWalletScopeString", "isSupportedScopeString", "isSupportedAccount", "isSupportedMethod", @@ -26,12 +32,6 @@ describe('@metamask/multichain', () => { "caip25EndowmentBuilder", "Caip25CaveatMutatorFactories", "removeScope", - "KnownWalletScopeString", - "KnownWalletRpcMethods", - "KnownRpcMethods", - "KnownWalletNamespaceRpcMethods", - "KnownNotifications", - "parseScopeString", ] `); }); diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 6c4d641f554..a70fce65088 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -10,7 +10,23 @@ export { export type { Caip25Authorization } from './scope/authorization'; export { validateAndNormalizeScopes } from './scope/authorization'; -export * from './scope/types'; +export { + KnownWalletRpcMethods, + KnownRpcMethods, + KnownWalletNamespaceRpcMethods, + KnownNotifications, +} from './scope/constants'; +export type { + ExternalScopeString, + ExternalScopeObject, + ExternalScopesObject, + ScopeString, + ScopeObject, + ScopesObject, + ScopedProperties, + NonWalletKnownCaipNamespace, +} from './scope/types'; +export { parseScopeString, KnownWalletScopeString } from './scope/types'; export { isSupportedScopeString, isSupportedAccount, diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts new file mode 100644 index 00000000000..ac1e4829d7d --- /dev/null +++ b/packages/multichain/src/scope/constants.ts @@ -0,0 +1,47 @@ +import MetaMaskOpenRPCDocument from '@metamask/api-specs'; +import type { KnownCaipNamespace } from '@metamask/utils'; + +// ScopeString for ecosystems that aren't chain specific +export enum KnownWalletScopeString { + Eip155 = 'wallet:eip155', +} + +// Known CAIP Namespaces excluding "wallet" +export type NonWalletKnownCaipNamespace = Exclude< + KnownCaipNamespace, + KnownCaipNamespace.Wallet +>; + +// Methods that do not belong to an ecosystem +export const KnownWalletRpcMethods: string[] = [ + 'wallet_registerOnboarding', + 'wallet_scanQRCode', +]; + +const WalletEip155Methods = ['wallet_addEthereumChain']; + +// All MetaMask methods, except for ones we have +// specified in the constants above +const Eip155Methods = MetaMaskOpenRPCDocument.methods + .map(({ name }: { name: string }) => name) + .filter((method: string) => !WalletEip155Methods.includes(method)) + .filter((method: string) => !KnownWalletRpcMethods.includes(method)); + +// Methods for ecosystem that are chain specific +export const KnownRpcMethods: Record = { + eip155: Eip155Methods, +}; + +// Methods for ecosystems that aren't chain specific +export const KnownWalletNamespaceRpcMethods: Record< + NonWalletKnownCaipNamespace, + string[] +> = { + eip155: WalletEip155Methods, +}; + +// Notifications +export const KnownNotifications: Record = + { + eip155: ['accountsChanged', 'chainChanged', 'eth_subscription'], + }; diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts index 72faf0e50d3..cec4acf4aad 100644 --- a/packages/multichain/src/scope/supported.test.ts +++ b/packages/multichain/src/scope/supported.test.ts @@ -1,14 +1,14 @@ -import { - isSupportedMethod, - isSupportedNotification, - isSupportedScopeString, -} from './supported'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, -} from './types'; +} from './constants'; +import { + isSupportedMethod, + isSupportedNotification, + isSupportedScopeString, +} from './supported'; describe('Scope Support', () => { describe('isSupportedNotification', () => { diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts index 52f351ea6c3..4cfe3fdbef5 100644 --- a/packages/multichain/src/scope/supported.ts +++ b/packages/multichain/src/scope/supported.ts @@ -8,14 +8,14 @@ import { parseCaipChainId, } from '@metamask/utils'; -import type { NonWalletKnownCaipNamespace, ExternalScopeString } from './types'; import { KnownNotifications, KnownRpcMethods, KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, - parseScopeString, -} from './types'; +} from './constants'; +import type { NonWalletKnownCaipNamespace, ExternalScopeString } from './types'; +import { parseScopeString } from './types'; export const isSupportedScopeString = ( scopeString: string, diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index bc15442ed40..2742bc5457f 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -1,4 +1,3 @@ -import MetaMaskOpenRPCDocument from '@metamask/api-specs'; import { isCaipNamespace, isCaipChainId, @@ -13,42 +12,6 @@ import type { Json, } from '@metamask/utils'; -export enum KnownWalletScopeString { - Eip155 = 'wallet:eip155', -} - -export type NonWalletKnownCaipNamespace = Extract< - KnownCaipNamespace, - KnownCaipNamespace.Eip155 ->; - -export const KnownWalletRpcMethods: string[] = [ - 'wallet_registerOnboarding', - 'wallet_scanQRCode', -]; -const WalletEip155Methods = ['wallet_addEthereumChain']; - -const Eip155Methods = MetaMaskOpenRPCDocument.methods - .map(({ name }: { name: string }) => name) - .filter((method: string) => !WalletEip155Methods.includes(method)) - .filter((method: string) => !KnownWalletRpcMethods.includes(method)); - -export const KnownRpcMethods: Record = { - eip155: Eip155Methods, -}; - -export const KnownWalletNamespaceRpcMethods: Record< - NonWalletKnownCaipNamespace, - string[] -> = { - eip155: WalletEip155Methods, -}; - -export const KnownNotifications: Record = - { - eip155: ['accountsChanged', 'chainChanged', 'eth_subscription'], - }; - // These External prefixed types represent the CAIP-217 // Scope and ScopeObject as defined in the spec. export type ExternalScopeString = CaipChainId | CaipNamespace; @@ -80,6 +43,10 @@ export type ScopesObject = Record & { [KnownCaipNamespace.Wallet]?: ScopeObject; }; +export type ScopedProperties = Record> & { + [KnownCaipNamespace.Wallet]?: Record; +}; + export const parseScopeString = ( scopeString: string, ): { @@ -98,6 +65,13 @@ export const parseScopeString = ( return {}; }; -export type ScopedProperties = Record> & { - [KnownCaipNamespace.Wallet]?: Record; -}; +// ScopeString for ecosystems that aren't chain specific +export enum KnownWalletScopeString { + Eip155 = 'wallet:eip155', +} + +// Known CAIP Namespaces excluding "wallet" +export type NonWalletKnownCaipNamespace = Exclude< + KnownCaipNamespace, + KnownCaipNamespace.Wallet +>; From 18d1112b95e756334fbf06d7dd5b9ec24a8783f7 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 08:55:08 -0700 Subject: [PATCH 060/146] remove jest.resetAllMocks --- packages/multichain/src/caip25Permission.test.ts | 4 ---- packages/multichain/src/scope/assert.test.ts | 4 ---- packages/multichain/src/scope/authorization.test.ts | 4 ---- packages/multichain/src/scope/validation.test.ts | 4 ---- 4 files changed, 16 deletions(-) diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index 900b89c907c..e2655c7288a 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -36,10 +36,6 @@ describe('endowment:caip25', () => { }); }); - afterEach(() => { - jest.resetAllMocks(); - }); - it('builds the expected permission specification', () => { const specification = caip25EndowmentBuilder.specificationBuilder({ methodHooks: { diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 9b09aa64379..e333cde8664 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -18,10 +18,6 @@ const validScopeObject: ScopeObject = { }; describe('Scope Assert', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - describe('assertScopeSupported', () => { const isChainIdSupported = jest.fn(); diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 55a184b364a..c4a9c3463d3 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -19,10 +19,6 @@ const validScopeObject: ExternalScopeObject = { }; describe('Scope Authorization', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - describe('validateAndNormalizeScopes', () => { it('validates the scopes', () => { try { diff --git a/packages/multichain/src/scope/validation.test.ts b/packages/multichain/src/scope/validation.test.ts index e8cfb962804..33bb343f3d9 100644 --- a/packages/multichain/src/scope/validation.test.ts +++ b/packages/multichain/src/scope/validation.test.ts @@ -8,10 +8,6 @@ const validScopeObject: ExternalScopeObject = { }; describe('Scope Validation', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - describe('isValidScope', () => { it.each([ [ From 1ba77c78b753ac9d410f48b84a58f63ab7c1ecfc Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 08:55:38 -0700 Subject: [PATCH 061/146] yarn lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 3493fb766fc..63495cca4d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2334,7 +2334,7 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^11.4.0, @metamask/controller-utils@workspace:packages/controller-utils": +"@metamask/controller-utils@npm:^11.3.0, @metamask/controller-utils@npm:^11.4.0, @metamask/controller-utils@workspace:packages/controller-utils": version: 0.0.0-use.local resolution: "@metamask/controller-utils@workspace:packages/controller-utils" dependencies: From bb50a193e8e684a4f885cc71a2319940b7259bd0 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 09:11:38 -0700 Subject: [PATCH 062/146] yarn --- packages/multichain/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index c06fe393968..e0ce902781f 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -48,7 +48,7 @@ }, "dependencies": { "@metamask/api-specs": "^0.10.12", - "@metamask/controller-utils": "^11.3.0", + "@metamask/controller-utils": "^11.4.0", "@metamask/eth-json-rpc-filters": "^7.0.0", "@metamask/rpc-errors": "^7.0.0", "@metamask/utils": "^9.1.0", diff --git a/yarn.lock b/yarn.lock index 63495cca4d1..05ba2455fed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2334,7 +2334,7 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^11.3.0, @metamask/controller-utils@npm:^11.4.0, @metamask/controller-utils@workspace:packages/controller-utils": +"@metamask/controller-utils@npm:^11.4.0, @metamask/controller-utils@workspace:packages/controller-utils": version: 0.0.0-use.local resolution: "@metamask/controller-utils@workspace:packages/controller-utils" dependencies: @@ -3050,7 +3050,7 @@ __metadata: dependencies: "@metamask/api-specs": "npm:^0.10.12" "@metamask/auto-changelog": "npm:^3.4.4" - "@metamask/controller-utils": "npm:^11.3.0" + "@metamask/controller-utils": "npm:^11.4.0" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" "@metamask/network-controller": "npm:^21.1.0" "@metamask/permission-controller": "npm:^11.0.2" From 7d32a0b28934ab979e4de515a0e709dac4825673 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 10:36:49 -0700 Subject: [PATCH 063/146] 100% coverage --- packages/multichain/jest.config.js | 8 +- ...ip-permission-adapter-eth-accounts.test.ts | 14 ++ ...permission-adapter-permittedChains.test.ts | 10 + .../multichain/src/caip25Permission.test.ts | 94 +++++++++- .../multichain/src/scope/supported.test.ts | 172 ++++++++++++++++++ packages/multichain/src/scope/supported.ts | 71 +++----- .../multichain/src/scope/transform.test.ts | 30 +++ .../multichain/src/scope/validation.test.ts | 9 + 8 files changed, 351 insertions(+), 57 deletions(-) diff --git a/packages/multichain/jest.config.js b/packages/multichain/jest.config.js index 1cadcfe8b28..ca084133399 100644 --- a/packages/multichain/jest.config.js +++ b/packages/multichain/jest.config.js @@ -17,10 +17,10 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 82.38, - functions: 87.37, - lines: 86.65, - statements: 87.09, + branches: 100, + functions: 100, + lines: 100, + statements: 100, }, }, }); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts index 6f043ed763b..f779f1f5764 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts @@ -105,6 +105,11 @@ describe('CAIP-25 eth_accounts adapters', () => { notifications: [], accounts: [], }, + wallet: { + methods: [], + notifications: [], + accounts: [], + }, }, isMultichainOrigin: false, }; @@ -155,6 +160,15 @@ describe('CAIP-25 eth_accounts adapters', () => { 'wallet:eip155:0x3', ], }, + wallet: { + methods: [], + notifications: [], + accounts: [ + 'wallet:eip155:0x1', + 'wallet:eip155:0x2', + 'wallet:eip155:0x3', + ], + }, }, isMultichainOrigin: false, }); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts index 1d55cf6f607..016067199a0 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.test.ts @@ -253,6 +253,11 @@ describe('CAIP-25 permittedChains adapters', () => { }, }, optionalScopes: { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, 'eip155:1': { methods: ['eth_chainId'], notifications: [], @@ -283,6 +288,11 @@ describe('CAIP-25 permittedChains adapters', () => { }, }, optionalScopes: { + wallet: { + methods: [], + notifications: [], + accounts: [], + }, 'eip155:1': { methods: ['eth_chainId'], notifications: [], diff --git a/packages/multichain/src/caip25Permission.test.ts b/packages/multichain/src/caip25Permission.test.ts index e2655c7288a..72929ba7c19 100644 --- a/packages/multichain/src/caip25Permission.test.ts +++ b/packages/multichain/src/caip25Permission.test.ts @@ -12,6 +12,7 @@ import { Caip25EndowmentPermissionName, Caip25CaveatMutatorFactories, removeScope, + Caip25CaveatFactoryFn, } from './caip25Permission'; import * as ScopeAssert from './scope/assert'; import * as ScopeAuthorization from './scope/authorization'; @@ -54,6 +55,23 @@ describe('endowment:caip25', () => { expect(specification.endowmentGetter()).toBeNull(); }); + it('builds the caveat', () => { + expect( + Caip25CaveatFactoryFn({ + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }), + ).toStrictEqual({ + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }); + }); + describe('caveat mutator removeScope', () => { it('can remove a caveat', () => { const ethereumGoerliCaveat = { @@ -477,9 +495,11 @@ describe('endowment:caip25', () => { isChainIdSupported: expect.any(Function), }), ); - const isChainIdSupportedBody = - MockScopeAssert.assertScopesSupported.mock.calls[0][1].isChainIdSupported.toString(); - expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + + MockScopeAssert.assertScopesSupported.mock.calls[0][1].isChainIdSupported( + '0x1', + ); + expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); }); it('asserts the validated and normalized optional scopes are supported', () => { @@ -543,9 +563,71 @@ describe('endowment:caip25', () => { isChainIdSupported: expect.any(Function), }), ); - const isChainIdSupportedBody = - MockScopeAssert.assertScopesSupported.mock.calls[1][1].isChainIdSupported.toString(); - expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + MockScopeAssert.assertScopesSupported.mock.calls[1][1].isChainIdSupported( + '0x1', + ); + expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); + }); + + it('does not throw if unable to find a network client for the chainId', () => { + MockScopeAuthorization.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { + 'eip155:1': { + methods: ['normalized_required'], + notifications: [], + accounts: [], + }, + }, + normalizedOptionalScopes: { + 'eip155:5': { + methods: ['normalized_optional'], + notifications: [], + accounts: [], + }, + }, + }); + findNetworkClientIdByChainId.mockImplementation(() => { + throw new Error('unable to find network client'); + }); + try { + validator({ + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: [], + accounts: ['eip155:1:0xdead'], + }, + }, + optionalScopes: { + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xbeef'], + }, + }, + isMultichainOrigin: true, + }, + }, + ], + date: 1234, + id: '1', + invoker: 'test.com', + parentCapability: Caip25EndowmentPermissionName, + }); + } catch (err) { + // noop + } + + expect( + MockScopeAssert.assertScopesSupported.mock.calls[0][1].isChainIdSupported( + '0x1', + ), + ).toBe(false); + expect(findNetworkClientIdByChainId).toHaveBeenCalledWith('0x1'); }); it('throws if the eth accounts specified in the normalized scopeObjects are not found in the wallet keyring', () => { diff --git a/packages/multichain/src/scope/supported.test.ts b/packages/multichain/src/scope/supported.test.ts index cec4acf4aad..76f41b9a44d 100644 --- a/packages/multichain/src/scope/supported.test.ts +++ b/packages/multichain/src/scope/supported.test.ts @@ -1,3 +1,5 @@ +import type { CaipAccountId } from '@metamask/utils'; + import { KnownNotifications, KnownRpcMethods, @@ -5,6 +7,7 @@ import { KnownWalletRpcMethods, } from './constants'; import { + isSupportedAccount, isSupportedMethod, isSupportedNotification, isSupportedScopeString, @@ -54,6 +57,7 @@ describe('Scope Support', () => { it('returns false otherwise', () => { expect(isSupportedMethod('eip155', 'anything else')).toBe(false); + expect(isSupportedMethod('wallet:unknown', 'anything else')).toBe(false); expect(isSupportedMethod('', '')).toBe(false); }); }); @@ -71,6 +75,18 @@ describe('Scope Support', () => { expect(isSupportedScopeString('eip155', jest.fn())).toBe(true); }); + it('returns false for unknown namespaces', () => { + expect(isSupportedScopeString('unknown', jest.fn())).toBe(false); + }); + + it('returns true for the wallet namespace with eip155 reference', () => { + expect(isSupportedScopeString('wallet:eip155', jest.fn())).toBe(true); + }); + + it('returns false for the wallet namespace with eip155 reference', () => { + expect(isSupportedScopeString('wallet:eip155', jest.fn())).toBe(true); + }); + it('returns true for the ethereum namespace when a network client exists for the reference', () => { const isChainIdSupportedMock = jest.fn().mockReturnValue(true); expect(isSupportedScopeString('eip155:1', isChainIdSupportedMock)).toBe( @@ -85,4 +101,160 @@ describe('Scope Support', () => { ); }); }); + + describe('isSupportedAccount', () => { + it.each([ + [ + true, + 'eoa account matching eip155 namespaced address exists', + 'eip155:1:0xdeadbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadbeef', + }, + ], + ], + [ + true, + 'eoa account matching eip155 namespaced address with different casing exists', + 'eip155:1:0xDEADbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadBEEF', + }, + ], + ], + [ + true, + 'erc4337 account matching eip155 namespaced address exists', + 'eip155:1:0xdeadbeef', + [ + { + type: 'eip155:erc4337', + address: '0xdeadbeef', + }, + ], + ], + [ + true, + 'erc4337 account matching eip155 namespaced address with different casing exists', + 'eip155:1:0xDEADbeef', + [ + { + type: 'eip155:erc4337', + address: '0xdeadBEEF', + }, + ], + ], + [ + false, + 'neither eoa or erc4337 account matching eip155 namespaced address exists', + 'eip155:1:0xdeadbeef', + [ + { + type: 'other', + address: '0xdeadbeef', + }, + ], + ], + + [ + true, + 'eoa account matching wallet:eip155 address exists', + 'wallet:eip155:0xdeadbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadbeef', + }, + ], + ], + [ + true, + 'eoa account matching wallet:eip155 address with different casing exists', + 'wallet:eip155:0xDEADbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadBEEF', + }, + ], + ], + [ + true, + 'erc4337 account matching wallet:eip155 address exists', + 'wallet:eip155:0xdeadbeef', + [ + { + type: 'eip155:erc4337', + address: '0xdeadbeef', + }, + ], + ], + [ + true, + 'erc4337 account matching wallet:eip155 address with different casing exists', + 'wallet:eip155:0xDEADbeef', + [ + { + type: 'eip155:erc4337', + address: '0xdeadBEEF', + }, + ], + ], + [ + false, + 'neither eoa or erc4337 account matching wallet:eip155 address exists', + 'wallet:eip155:0xdeadbeef', + [ + { + type: 'other', + address: '0xdeadbeef', + }, + ], + ], + [ + false, + 'wallet namespace with unknown reference', + 'wallet:foobar:0xdeadbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadbeef', + }, + { + type: 'eip155:erc4337', + address: '0xdeadbeef', + }, + ], + ], + [ + false, + 'unknown namespace', + 'foo:bar:0xdeadbeef', + [ + { + type: 'eip155:eoa', + address: '0xdeadbeef', + }, + { + type: 'eip155:erc4337', + address: '0xdeadbeef', + }, + ], + ], + ])( + 'returns %s if %s', + (result, _desc, account, getInternalAccountsValue) => { + const getInternalAccounts = jest + .fn() + .mockReturnValue(getInternalAccountsValue); + expect( + isSupportedAccount(account as CaipAccountId, getInternalAccounts), + ).toBe(result); + }, + ); + }); }); diff --git a/packages/multichain/src/scope/supported.ts b/packages/multichain/src/scope/supported.ts index 4cfe3fdbef5..42f6ccd3186 100644 --- a/packages/multichain/src/scope/supported.ts +++ b/packages/multichain/src/scope/supported.ts @@ -1,12 +1,6 @@ import { toHex, isEqualCaseInsensitive } from '@metamask/controller-utils'; -import type { CaipAccountId, Hex } from '@metamask/utils'; -import { - isCaipChainId, - isCaipNamespace, - KnownCaipNamespace, - parseCaipAccountId, - parseCaipChainId, -} from '@metamask/utils'; +import type { CaipAccountId, Hex, CaipChainId } from '@metamask/utils'; +import { KnownCaipNamespace, parseCaipAccountId } from '@metamask/utils'; import { KnownNotifications, @@ -21,36 +15,16 @@ export const isSupportedScopeString = ( scopeString: string, isChainIdSupported: (chainId: Hex) => boolean, ) => { - const isNamespaceScoped = isCaipNamespace(scopeString); - const isChainScoped = isCaipChainId(scopeString); - - if (isNamespaceScoped) { - switch (scopeString) { - case KnownCaipNamespace.Wallet: - return true; - case KnownCaipNamespace.Eip155: - return true; - default: - return false; - } - } + const { namespace, reference } = parseScopeString(scopeString as CaipChainId); - if (isChainScoped) { - const { namespace, reference } = parseCaipChainId(scopeString); - switch (namespace) { - case KnownCaipNamespace.Wallet: - if (reference === KnownCaipNamespace.Eip155) { - return true; - } - return false; - case KnownCaipNamespace.Eip155: - return isChainIdSupported(toHex(reference)); - default: - return false; - } + switch (namespace) { + case KnownCaipNamespace.Wallet: + return !reference || reference === KnownCaipNamespace.Eip155; + case KnownCaipNamespace.Eip155: + return !reference || isChainIdSupported(toHex(reference)); + default: + return false; } - - return false; }; export const isSupportedAccount = ( @@ -59,20 +33,23 @@ export const isSupportedAccount = ( ) => { const { address, - chain: { namespace }, + chain: { namespace, reference }, } = parseCaipAccountId(account); + + const isSupportedEip155Account = () => + getInternalAccounts().some( + (internalAccount) => + ['eip155:eoa', 'eip155:erc4337'].includes(internalAccount.type) && + isEqualCaseInsensitive(address, internalAccount.address), + ); + switch (namespace) { + case KnownCaipNamespace.Wallet: + return reference === KnownCaipNamespace.Eip155 + ? isSupportedEip155Account() + : false; case KnownCaipNamespace.Eip155: - try { - return getInternalAccounts().some( - (internalAccount) => - ['eip155:eoa', 'eip155:erc4337'].includes(internalAccount.type) && - isEqualCaseInsensitive(address, internalAccount.address), - ); - } catch (err) { - console.log('failed to check if account is supported by wallet', err); - } - return false; + return isSupportedEip155Account(); default: return false; } diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index afdd3ae2a35..ea19dab97f0 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -168,6 +168,21 @@ describe('Scope Transform', () => { ...validScopeObject, rpcDocuments: ['a', 'b', 'c'], }); + + expect( + mergeScopeObject( + { + ...validScopeObject, + }, + { + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcDocuments: ['a', 'b', 'c'], + }); }); it('returns an object with the unique set of rpcEndpoints', () => { @@ -201,6 +216,21 @@ describe('Scope Transform', () => { ...validScopeObject, rpcEndpoints: ['a', 'b', 'c'], }); + + expect( + mergeScopeObject( + { + ...validScopeObject, + }, + { + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c'], + }, + ), + ).toStrictEqual({ + ...validScopeObject, + rpcEndpoints: ['a', 'b', 'c'], + }); }); }); diff --git a/packages/multichain/src/scope/validation.test.ts b/packages/multichain/src/scope/validation.test.ts index 33bb343f3d9..253e54a99bd 100644 --- a/packages/multichain/src/scope/validation.test.ts +++ b/packages/multichain/src/scope/validation.test.ts @@ -37,6 +37,15 @@ describe('Scope Validation', () => { references: ['5'], }, ], + [ + false, + 'the scopeString is a valid CAIP namespace but references are invalid CAIP references', + 'eip155', + { + ...validScopeObject, + references: ['@'], + }, + ], [ false, 'methods contains empty string', From f0953702046b47ca3108c8874fc187aee9f24e69 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 23 Oct 2024 11:10:13 -0700 Subject: [PATCH 064/146] Remove accountsChanged and chainChanged from KnownNotifications (since they are implicitly granted now) --- packages/multichain/src/scope/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index ac1e4829d7d..81fbd4db63c 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -43,5 +43,5 @@ export const KnownWalletNamespaceRpcMethods: Record< // Notifications export const KnownNotifications: Record = { - eip155: ['accountsChanged', 'chainChanged', 'eth_subscription'], + eip155: ['eth_subscription'], }; From 491552f21512e222c8b387124039e240b25640de Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 24 Oct 2024 15:11:57 -0700 Subject: [PATCH 065/146] Update packages/multichain/src/scope/transform.test.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/scope/transform.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/multichain/src/scope/transform.test.ts b/packages/multichain/src/scope/transform.test.ts index ea19dab97f0..a98c2986dd0 100644 --- a/packages/multichain/src/scope/transform.test.ts +++ b/packages/multichain/src/scope/transform.test.ts @@ -52,16 +52,16 @@ describe('Scope Transform', () => { }); it('returns one deep cloned scope per `references` element', () => { - const noramlizedScopes = normalizeScope('eip155', { + const normalizedScopes = normalizeScope('eip155', { ...validScopeObject, references: ['1', '5'], }); - expect(noramlizedScopes['eip155:1']).not.toBe( - noramlizedScopes['eip155:5'], + expect(normalizedScopes['eip155:1']).not.toBe( + normalizedScopes['eip155:5'], ); - expect(noramlizedScopes['eip155:1'].methods).not.toBe( - noramlizedScopes['eip155:5'].methods, + expect(normalizedScopes['eip155:1'].methods).not.toBe( + normalizedScopes['eip155:5'].methods, ); }); }); From 0d167a3d4239ed5734f38ac906b8226985ba35d0 Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 21 Nov 2024 14:26:01 -0800 Subject: [PATCH 066/146] CAIP Multichain API with permission refactor changes (#4961) ## Explanation ~~This diff is a bit messy since it also brings in the [core PR that refactors the CAIP-25 permission](https://github.com/MetaMask/core/pull/4950) which the [caip-multichain-api](https://github.com/MetaMask/core/tree/caip-multichain-api) branch doesn't have yet.~~ The main thing this PR does is adds `getSessionScopes()` which massages the new CAIP-25 permission into a `NormalizedScopesObject` ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --------- Co-authored-by: Alex Donesky --- packages/multichain/package.json | 2 +- .../caip-permission-adapter-middleware.ts | 18 ++-- ...-permission-adapter-session-scopes.test.ts | 87 +++++++++++++++++++ .../caip-permission-adapter-session-scopes.ts | 78 +++++++++++++++++ .../src/handlers/wallet-getSession.test.ts | 66 ++++++++++++-- .../src/handlers/wallet-getSession.ts | 11 +-- .../src/handlers/wallet-invokeMethod.test.ts | 81 +++++++++++++---- .../src/handlers/wallet-invokeMethod.ts | 14 +-- packages/multichain/src/index.test.ts | 17 ++++ packages/multichain/src/index.ts | 4 +- packages/multichain/src/scope/assert.test.ts | 45 +++++++++- packages/multichain/src/scope/assert.ts | 2 +- .../src/scope/authorization.test.ts | 6 ++ .../multichain/src/scope/authorization.ts | 10 +-- packages/multichain/src/scope/filter.ts | 10 +-- packages/multichain/src/scope/types.ts | 6 +- yarn.lock | 15 +--- 17 files changed, 393 insertions(+), 79 deletions(-) create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts create mode 100644 packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 5a90288e99c..1daaab643f0 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -59,7 +59,7 @@ }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", - "@metamask/json-rpc-engine": "^9.0.3", + "@metamask/json-rpc-engine": "^10.0.1", "@metamask/network-controller": "^22.0.2", "@metamask/permission-controller": "^11.0.3", "@open-rpc/meta-schema": "^1.14.6", diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 865a4cccfcb..12402b17f9f 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -11,8 +11,9 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import { KnownWalletScopeString, type ScopeString } from '../scope/types'; +import { KnownWalletScopeString } from '../scope/constants'; +import type { InternalScopeString } from '../scope/types'; +import { getSessionScopes } from './caip-permission-adapter-session-scopes'; /** * Middleware to handle CAIP-25 permission requests. @@ -61,17 +62,14 @@ export async function caipPermissionAdapterMiddleware( const { chainId } = hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - const scope: ScopeString = `eip155:${parseInt(chainId, 16)}`; + const scope: InternalScopeString = `eip155:${parseInt(chainId, 16)}`; - const scopesObject = mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - ); + const sesionScopes = getSessionScopes(caveat.value); if ( - !scopesObject[scope]?.methods?.includes(method) && - !scopesObject[KnownWalletScopeString.Eip155]?.methods?.includes(method) && - !scopesObject.wallet?.methods?.includes(method) + !sesionScopes[scope]?.methods?.includes(method) && + !sesionScopes[KnownWalletScopeString.Eip155]?.methods?.includes(method) && + !sesionScopes.wallet?.methods?.includes(method) ) { return end(providerErrors.unauthorized()); } diff --git a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts new file mode 100644 index 00000000000..05f924d942d --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts @@ -0,0 +1,87 @@ +import { + KnownNotifications, + KnownRpcMethods, + KnownWalletNamespaceRpcMethods, + KnownWalletRpcMethods, +} from '../scope/constants'; +import { getSessionScopes } from './caip-permission-adapter-session-scopes'; + +describe('CAIP-25 session scopes adapters', () => { + describe('getSessionScopes', () => { + it('returns a NormalizedScopesObject for the wallet scope', () => { + const result = getSessionScopes({ + requiredScopes: {}, + optionalScopes: { + wallet: { + accounts: [], + }, + }, + }); + + expect(result).toStrictEqual({ + wallet: { + methods: KnownWalletRpcMethods, + notifications: [], + accounts: [], + }, + }); + }); + + it('returns a NormalizedScopesObject for the wallet:eip155 scope', () => { + const result = getSessionScopes({ + requiredScopes: {}, + optionalScopes: { + 'wallet:eip155': { + accounts: ['wallet:eip155:0xdeadbeef'], + }, + }, + }); + + expect(result).toStrictEqual({ + 'wallet:eip155': { + methods: KnownWalletNamespaceRpcMethods.eip155, + notifications: [], + accounts: ['wallet:eip155:0xdeadbeef'], + }, + }); + }); + + it('returns a NormalizedScopesObject with empty methods and notifications for scope with wallet namespace and unknown reference', () => { + const result = getSessionScopes({ + requiredScopes: {}, + optionalScopes: { + 'wallet:foobar': { + accounts: ['wallet:foobar:0xdeadbeef'], + }, + }, + }); + + expect(result).toStrictEqual({ + 'wallet:foobar': { + methods: [], + notifications: [], + accounts: ['wallet:foobar:0xdeadbeef'], + }, + }); + }); + + it('returns a NormalizedScopesObject for a eip155 namespaced scope', () => { + const result = getSessionScopes({ + requiredScopes: {}, + optionalScopes: { + 'eip155:1': { + accounts: ['eip155:1:0xdeadbeef'], + }, + }, + }); + + expect(result).toStrictEqual({ + 'eip155:1': { + methods: KnownRpcMethods.eip155, + notifications: KnownNotifications.eip155, + accounts: ['eip155:1:0xdeadbeef'], + }, + }); + }); + }); +}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts new file mode 100644 index 00000000000..8de3698bbba --- /dev/null +++ b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts @@ -0,0 +1,78 @@ +import { KnownCaipNamespace } from '@metamask/utils'; + +import type { Caip25CaveatValue } from '../caip25Permission'; +import { + KnownNotifications, + KnownRpcMethods, + KnownWalletNamespaceRpcMethods, + KnownWalletRpcMethods, +} from '../scope/constants'; +import { mergeScopes } from '../scope/transform'; +import type { + InternalScopesObject, + NonWalletKnownCaipNamespace, + NormalizedScopesObject, +} from '../scope/types'; +import { parseScopeString } from '../scope/types'; + +/** + * Converts an InternalScopesObject to a NormalizedScopesObject. + * @param internalScopesObject - The InternalScopesObject to convert. + * @returns A NormalizedScopesObject. + */ +const getNormalizedScopesObject = ( + internalScopesObject: InternalScopesObject, +) => { + const normalizedScopes: NormalizedScopesObject = {}; + + Object.entries(internalScopesObject).forEach( + ([_scopeString, { accounts }]) => { + const scopeString = _scopeString as keyof typeof internalScopesObject; + const { namespace, reference } = parseScopeString(scopeString); + let methods: string[] = []; + let notifications: string[] = []; + + if (namespace === KnownCaipNamespace.Wallet) { + if (reference) { + methods = + KnownWalletNamespaceRpcMethods[ + reference as NonWalletKnownCaipNamespace + ] ?? []; + } else { + methods = KnownWalletRpcMethods; + } + } else { + methods = + KnownRpcMethods[namespace as NonWalletKnownCaipNamespace] ?? []; + notifications = + KnownNotifications[namespace as NonWalletKnownCaipNamespace] ?? []; + } + + normalizedScopes[scopeString] = { + methods, + notifications, + accounts, + }; + }, + ); + + return normalizedScopes; +}; + +/** + * Takes the scopes from an endowment:caip25 permission caveat value, + * hydrates them with supported methods and notifications, and returns a NormalizedScopesObject. + * @param caip25CaveatValue - The CAIP-25 CaveatValue to convert. + * @returns A NormalizedScopesObject. + */ +export const getSessionScopes = ( + caip25CaveatValue: Pick< + Caip25CaveatValue, + 'requiredScopes' | 'optionalScopes' + >, +) => { + return mergeScopes( + getNormalizedScopesObject(caip25CaveatValue.requiredScopes), + getNormalizedScopesObject(caip25CaveatValue.optionalScopes), + ); +}; diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index ca74cc9b909..25833942035 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -1,11 +1,19 @@ import type { JsonRpcRequest } from '@metamask/utils'; +import * as PermissionAdapterSessionScopes from '../adapters/caip-permission-adapter-session-scopes'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; import { walletGetSession } from './wallet-getSession'; +jest.mock('../adapters/caip-permission-adapter-session-scopes', () => ({ + getSessionScopes: jest.fn(), +})); +const MockPermissionAdapterSessionScopes = jest.mocked( + PermissionAdapterSessionScopes, +); + const baseRequest: JsonRpcRequest & { origin: string } = { origin: 'http://test.com', jsonrpc: '2.0' as const, @@ -21,25 +29,17 @@ const createMockedHandler = () => { value: { requiredScopes: { 'eip155:1': { - methods: ['eth_call'], - notifications: [], accounts: [], }, 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], accounts: [], }, }, optionalScopes: { 'eip155:1': { - methods: ['net_version'], - notifications: ['chainChanged'], accounts: [], }, wallet: { - methods: ['wallet_watchAsset'], - notifications: [], accounts: [], }, }, @@ -67,6 +67,10 @@ const createMockedHandler = () => { }; describe('wallet_getSession', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { const { handler, getCaveat } = createMockedHandler(); @@ -90,9 +94,53 @@ describe('wallet_getSession', () => { }); }); - it('returns the merged scopes', async () => { + it('gets the session scopes from the CAIP-25 caveat value', async () => { + const { handler } = createMockedHandler(); + + await handler(baseRequest); + expect( + MockPermissionAdapterSessionScopes.getSessionScopes, + ).toHaveBeenCalledWith({ + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + 'eip155:5': { + accounts: [], + }, + }, + optionalScopes: { + 'eip155:1': { + accounts: [], + }, + wallet: { + accounts: [], + }, + }, + }); + }); + + it('returns the session scopes', async () => { const { handler, response } = createMockedHandler(); + MockPermissionAdapterSessionScopes.getSessionScopes.mockReturnValue({ + 'eip155:1': { + methods: ['eth_call', 'net_version'], + notifications: ['chainChanged'], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + }); + await handler(baseRequest); expect(response.result).toStrictEqual({ sessionScopes: { diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index ad3e4e5569b..6a8f4bf2fb6 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -1,13 +1,13 @@ import type { Caveat } from '@metamask/permission-controller'; import type { JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils'; +import type { NormalizedScopesObject } from 'src/scope/types'; +import { getSessionScopes } from '../adapters/caip-permission-adapter-session-scopes'; import type { Caip25CaveatValue } from '../caip25Permission'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import type { ScopesObject } from '../scope/types'; /** * Handler for the `wallet_getSession` RPC method. @@ -21,7 +21,7 @@ import type { ScopesObject } from '../scope/types'; */ async function walletGetSessionHandler( request: JsonRpcRequest & { origin: string }, - response: JsonRpcSuccess<{ sessionScopes: ScopesObject }>, + response: JsonRpcSuccess<{ sessionScopes: NormalizedScopesObject }>, _next: () => void, end: () => void, hooks: { @@ -49,10 +49,7 @@ async function walletGetSessionHandler( } response.result = { - sessionScopes: mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - ), + sessionScopes: getSessionScopes(caveat.value), }; return end(); } diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index 208bccc3371..a608e2866f7 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -1,12 +1,20 @@ import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; import type { JsonRpcRequest } from '@metamask/utils'; +import * as PermissionAdapterSessionScopes from '../adapters/caip-permission-adapter-session-scopes'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; import { walletInvokeMethod } from './wallet-invokeMethod'; +jest.mock('../adapters/caip-permission-adapter-session-scopes', () => ({ + getSessionScopes: jest.fn(), +})); +const MockPermissionAdapterSessionScopes = jest.mocked( + PermissionAdapterSessionScopes, +); + const createMockedRequest = () => ({ jsonrpc: '2.0' as const, id: 0, @@ -30,30 +38,17 @@ const createMockedHandler = () => { value: { requiredScopes: { 'eip155:1': { - methods: ['eth_call'], - notifications: [], accounts: [], }, 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], accounts: [], }, }, optionalScopes: { 'eip155:1': { - methods: ['net_version'], - notifications: [], accounts: [], }, wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - unhandled: { - methods: ['foobar'], - notifications: [], accounts: [], }, }, @@ -88,6 +83,35 @@ const createMockedHandler = () => { }; describe('wallet_invokeMethod', () => { + beforeEach(() => { + MockPermissionAdapterSessionScopes.getSessionScopes.mockReturnValue({ + 'eip155:1': { + methods: ['eth_call', 'net_version'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['eth_chainId'], + notifications: [], + accounts: [], + }, + wallet: { + methods: ['wallet_watchAsset'], + notifications: [], + accounts: [], + }, + 'unknown:scope': { + methods: ['foobar'], + notifications: [], + accounts: [], + }, + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { const request = createMockedRequest(); const { handler, getCaveat } = createMockedHandler(); @@ -99,6 +123,33 @@ describe('wallet_invokeMethod', () => { ); }); + it('gets the session scopes from the CAIP-25 caveat value', async () => { + const request = createMockedRequest(); + const { handler } = createMockedHandler(); + await handler(request); + expect( + MockPermissionAdapterSessionScopes.getSessionScopes, + ).toHaveBeenCalledWith({ + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + 'eip155:5': { + accounts: [], + }, + }, + optionalScopes: { + 'eip155:1': { + accounts: [], + }, + wallet: { + accounts: [], + }, + }, + isMultichainOrigin: true, + }); + }); + it('throws an unauthorized error when there is no CAIP-25 endowment permission', async () => { const request = createMockedRequest(); const { handler, getCaveat, end } = createMockedHandler(); @@ -152,7 +203,7 @@ describe('wallet_invokeMethod', () => { expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); }); - it('throws an internal error for authorized but unhandled scopes', async () => { + it('throws an internal error for authorized but unsupported scopes', async () => { const request = createMockedRequest(); const { handler, end } = createMockedHandler(); @@ -160,7 +211,7 @@ describe('wallet_invokeMethod', () => { ...request, params: { ...request.params, - scope: 'unhandled', + scope: 'unknown:scope', request: { ...request.params.request, method: 'foobar', diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 3df3ca8346f..4e9f6002bd5 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -7,13 +7,14 @@ import type { } from '@metamask/utils'; import { numberToHex } from '@metamask/utils'; +import { getSessionScopes } from '../adapters/caip-permission-adapter-session-scopes'; import type { Caip25CaveatValue } from '../caip25Permission'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { mergeScopes } from '../scope/transform'; -import type { ScopeString } from '../scope/types'; +import { assertIsInternalScopeString } from '../scope/assert'; +import type { ExternalScopeString } from '../scope/types'; import { parseScopeString } from '../scope/types'; /** @@ -44,10 +45,12 @@ async function walletInvokeMethodHandler( }, ) { const { scope, request: wrappedRequest } = request.params as { - scope: ScopeString; + scope: ExternalScopeString; request: JsonRpcRequest; }; + assertIsInternalScopeString(scope); + let caveat; try { caveat = hooks.getCaveat( @@ -62,10 +65,7 @@ async function walletInvokeMethodHandler( return end(providerErrors.unauthorized()); } - const scopeObject = mergeScopes( - caveat.value.requiredScopes, - caveat.value.optionalScopes, - )[scope]; + const scopeObject = getSessionScopes(caveat.value)[scope]; if (!scopeObject?.methods?.includes(wrappedRequest.method)) { return end(providerErrors.unauthorized()); diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 61f0fdcc429..296dbb912b4 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -9,17 +9,34 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", + "walletGetSession", + "walletInvokeMethod", + "walletRevokeSession", + "multichainMethodCallValidatorMiddleware", + "MultichainMiddlewareManager", + "MultichainSubscriptionManager", + "assertScopeSupported", + "assertScopesSupported", "validateAndNormalizeScopes", + "bucketScopes", + "bucketScopesBySupport", + "filterScopesSupported", "KnownWalletRpcMethods", "KnownRpcMethods", "KnownWalletNamespaceRpcMethods", "KnownNotifications", "KnownWalletScopeString", "parseScopeString", + "isSupportedScopeString", + "isSupportedAccount", + "isSupportedMethod", + "isSupportedNotification", "normalizeScope", "mergeScopeObject", "mergeScopes", "normalizeAndMergeScopes", + "isValidScope", + "getValidScopes", "Caip25CaveatType", "createCaip25Caveat", "Caip25EndowmentPermissionName", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 82281c91983..481def28f1a 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -42,7 +42,7 @@ export type { ScopedProperties, NonWalletKnownCaipNamespace, } from './scope/types'; -export { parseScopeString, KnownWalletScopeString } from './scope/types'; +export { parseScopeString } from './scope/types'; // Do these need to be exported? export { isSupportedScopeString, @@ -57,7 +57,7 @@ export { normalizeAndMergeScopes, } from './scope/transform'; // does this need to be exported? -export { isValidScope, validateScopes } from './scope/validation'; +export { isValidScope, getValidScopes } from './scope/validation'; export type { Caip25CaveatValue } from './caip25Permission'; export { diff --git a/packages/multichain/src/scope/assert.test.ts b/packages/multichain/src/scope/assert.test.ts index 0fd23b5bf61..2b27abd6728 100644 --- a/packages/multichain/src/scope/assert.test.ts +++ b/packages/multichain/src/scope/assert.test.ts @@ -5,6 +5,7 @@ import { assertScopesSupported, assertIsExternalScopesObject, assertIsInternalScopesObject, + assertIsInternalScopeString, } from './assert'; import { Caip25Errors } from './errors'; import * as Supported from './supported'; @@ -18,6 +19,7 @@ jest.mock('./supported', () => ({ jest.mock('@metamask/utils', () => ({ ...jest.requireActual('@metamask/utils'), + isCaipChainId: jest.fn(), isCaipReference: jest.fn(), isCaipAccountId: jest.fn(), })); @@ -33,6 +35,7 @@ const validScopeObject: NormalizedScopeObject = { describe('Scope Assert', () => { beforeEach(() => { + MockUtils.isCaipChainId.mockImplementation(() => true); MockUtils.isCaipReference.mockImplementation(() => true); MockUtils.isCaipAccountId.mockImplementation(() => true); }); @@ -261,7 +264,7 @@ describe('Scope Assert', () => { }); it('throws an error if passed an object with a key that is not a valid ExternalScopeString', () => { - jest.spyOn(Utils, 'isCaipReference').mockImplementation(() => false); + MockUtils.isCaipChainId.mockReturnValue(false); expect(() => assertIsExternalScopesObject({ 'invalid-scope-string': {} }), @@ -480,6 +483,44 @@ describe('Scope Assert', () => { }); }); + describe('assertIsInternalScopeString', () => { + it('throws an error if the value is not a string', () => { + expect(() => assertIsInternalScopeString({})).toThrow( + 'scopeString is not a valid InternalScopeString', + ); + expect(() => assertIsInternalScopeString(123)).toThrow( + 'scopeString is not a valid InternalScopeString', + ); + expect(() => assertIsInternalScopeString(undefined)).toThrow( + 'scopeString is not a valid InternalScopeString', + ); + expect(() => assertIsInternalScopeString(null)).toThrow( + 'scopeString is not a valid InternalScopeString', + ); + }); + + it("does not throw an error if the value is 'wallet'", () => { + expect(assertIsInternalScopeString('wallet')).toBeUndefined(); + expect(MockUtils.isCaipChainId).not.toHaveBeenCalled(); + }); + + it('does not throw an error if the value is a valid CAIP-2 Chain ID', () => { + MockUtils.isCaipChainId.mockReturnValue(true); + + expect(assertIsInternalScopeString('scopeString')).toBeUndefined(); + expect(MockUtils.isCaipChainId).toHaveBeenCalledWith('scopeString'); + }); + + it('throws an error if the value is not a valid CAIP-2 Chain ID', () => { + MockUtils.isCaipChainId.mockReturnValue(false); + + expect(() => assertIsInternalScopeString('scopeString')).toThrow( + 'scopeString is not a valid InternalScopeString', + ); + expect(MockUtils.isCaipChainId).toHaveBeenCalledWith('scopeString'); + }); + }); + describe('assertIsInternalScopesObject', () => { it('does not throw if passed obj is a valid InternalScopesObject with all valid properties', () => { const obj = { @@ -509,7 +550,7 @@ describe('Scope Assert', () => { }); it('throws an error if passed an object with a key that is not a valid InternalScopeString', () => { - jest.spyOn(Utils, 'isCaipReference').mockImplementation(() => false); + MockUtils.isCaipChainId.mockReturnValue(false); expect(() => assertIsInternalScopesObject({ 'invalid-scope-string': {} }), diff --git a/packages/multichain/src/scope/assert.ts b/packages/multichain/src/scope/assert.ts index 0d2c8c16cb7..873c577575e 100644 --- a/packages/multichain/src/scope/assert.ts +++ b/packages/multichain/src/scope/assert.ts @@ -219,7 +219,7 @@ function assertIsInternalScopeObject( * Asserts that a scope string is a valid InternalScopeString. * @param scopeString - The scope string to assert. */ -function assertIsInternalScopeString( +export function assertIsInternalScopeString( scopeString: unknown, ): asserts scopeString is InternalScopeString { if ( diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 57555dfbcef..2514c630dce 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -1,8 +1,14 @@ import { bucketScopes, validateAndNormalizeScopes } from './authorization'; +import * as Filter from './filter'; import * as Transform from './transform'; import type { ExternalScopeObject } from './types'; import * as Validation from './validation'; +jest.mock('./filter', () => ({ + bucketScopesBySupport: jest.fn(), +})); +const MockFilter = jest.mocked(Filter); + jest.mock('./validation', () => ({ getValidScopes: jest.fn(), })); diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index f26e4798d40..b3f00cba09e 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -1,5 +1,6 @@ import type { Hex, Json } from '@metamask/utils'; +import { bucketScopesBySupport } from './filter'; import { normalizeAndMergeScopes } from './transform'; import type { ExternalScopesObject, @@ -7,7 +8,6 @@ import type { NormalizedScopesObject, } from './types'; import { getValidScopes } from './validation'; -import { bucketScopesBySupport } from './filter'; /** * Represents the parameters of a [CAIP-25](https://chainagnostic.org/CAIPs/caip-25) request. @@ -54,7 +54,7 @@ export const validateAndNormalizeScopes = ( }; export const bucketScopes = ( - scopes: InternalScopesObject, + scopes: NormalizedScopesObject, { isChainIdSupported, isChainIdSupportable, @@ -63,9 +63,9 @@ export const bucketScopes = ( isChainIdSupportable: (chainId: Hex) => boolean; }, ): { - supportedScopes: InternalScopesObject; - supportableScopes: InternalScopesObject; - unsupportableScopes: InternalScopesObject; + supportedScopes: NormalizedScopesObject; + supportableScopes: NormalizedScopesObject; + unsupportableScopes: NormalizedScopesObject; } => { const { supportedScopes, unsupportedScopes: maybeSupportableScopes } = bucketScopesBySupport(scopes, { diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index 68544583981..b8ab92f805e 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -1,18 +1,18 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { assertScopeSupported } from './assert'; -import type { InternalScopesObject } from './types'; +import type { NormalizedScopesObject } from './types'; export const bucketScopesBySupport = ( - scopes: InternalScopesObject, + scopes: NormalizedScopesObject, { isChainIdSupported, }: { isChainIdSupported: (chainId: Hex) => boolean; }, ) => { - const supportedScopes: InternalScopesObject = {}; - const unsupportedScopes: InternalScopesObject = {}; + const supportedScopes: NormalizedScopesObject = {}; + const unsupportedScopes: NormalizedScopesObject = {}; for (const [scopeString, scopeObject] of Object.entries(scopes)) { try { @@ -29,7 +29,7 @@ export const bucketScopesBySupport = ( }; export const filterScopesSupported = ( - scopes: InternalScopesObject, + scopes: NormalizedScopesObject, { isChainIdSupported, }: { diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index f639c58d2ea..b13b5edae75 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -60,7 +60,8 @@ export type InternalScopesObject = Record & { * [CAIP-217](https://chainagnostic.org/CAIPs/caip-217), with the exception that * we resolve the `references` property into a scopeObject per reference and * assign an empty array to the `accounts` property if not already defined - * to more easily read chain specific permissions. + * to more easily perform support checks for `wallet_createSession` requests. + * Also used as the return type for `wallet_createSession` and `wallet_sessionChanged`. */ export type NormalizedScopeObject = { methods: string[]; @@ -74,7 +75,8 @@ export type NormalizedScopeObject = { * [CAIP-217](https://chainagnostic.org/CAIPs/caip-217), with the exception that * we resolve the `references` property into a scopeObject per reference and * assign an empty array to the `accounts` property if not already defined - * to more easily read chain specific permissions. + * to more easily perform support checks for `wallet_createSession` requests. + * Also used as the return type for `wallet_createSession` and `wallet_sessionChanged`. */ export type NormalizedScopesObject = Record< CaipChainId, diff --git a/yarn.lock b/yarn.lock index da7bc2a801f..8c1a8b98613 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2932,17 +2932,6 @@ __metadata: languageName: node linkType: hard -"@metamask/json-rpc-engine@npm:^9.0.3": - version: 9.0.3 - resolution: "@metamask/json-rpc-engine@npm:9.0.3" - dependencies: - "@metamask/rpc-errors": "npm:^6.3.1" - "@metamask/safe-event-emitter": "npm:^3.0.0" - "@metamask/utils": "npm:^9.1.0" - checksum: 10/23a3cafb5869f6d5867105e3570ac4e214a72dda0b4b428cde6bae8856ec838c822b174f8cea054108122531d662cf93a65e92e1ee07da0485d5d0c0e5a1fca6 - languageName: node - linkType: hard - "@metamask/json-rpc-middleware-stream@npm:^8.0.5, @metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream": version: 0.0.0-use.local resolution: "@metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream" @@ -3087,7 +3076,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/controller-utils": "npm:^11.4.3" "@metamask/eth-json-rpc-filters": "npm:^7.0.0" - "@metamask/json-rpc-engine": "npm:^9.0.3" + "@metamask/json-rpc-engine": "npm:^10.0.1" "@metamask/network-controller": "npm:^22.0.2" "@metamask/permission-controller": "npm:^11.0.3" "@metamask/rpc-errors": "npm:^7.0.1" @@ -3495,7 +3484,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/rpc-errors@npm:^6.2.1, @metamask/rpc-errors@npm:^6.3.1": +"@metamask/rpc-errors@npm:^6.2.1": version: 6.3.1 resolution: "@metamask/rpc-errors@npm:6.3.1" dependencies: From 17af3953b1595d7ec7466e07aabc38b467903f3e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 21 Nov 2024 15:44:03 -0800 Subject: [PATCH 067/146] export caipPermissionAdapterMiddleware --- packages/multichain/src/index.test.ts | 1 + packages/multichain/src/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 296dbb912b4..654d802d8f0 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -9,6 +9,7 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", + "caipPermissionAdapterMiddleware", "walletGetSession", "walletInvokeMethod", "walletRevokeSession", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 481def28f1a..0260e269760 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -7,6 +7,7 @@ export { addPermittedEthChainId, setPermittedEthChainIds, } from './adapters/caip-permission-adapter-permittedChains'; +export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; export { walletGetSession } from './handlers/wallet-getSession'; export { walletInvokeMethod } from './handlers/wallet-invokeMethod'; From 62975b62dfcbd7baff08d27b9eccf5b67cae667a Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 21 Nov 2024 15:46:57 -0800 Subject: [PATCH 068/146] Caip multichain api normalized to internal (#4964) ## Explanation * Add getInternalScopesObject * Export getInternalScopesObject and getSessionScopes --------- Co-authored-by: Alex Donesky --- ...-permission-adapter-session-scopes.test.ts | 31 ++++++++++++++++++- .../caip-permission-adapter-session-scopes.ts | 23 ++++++++++++++ packages/multichain/src/index.test.ts | 2 ++ packages/multichain/src/index.ts | 4 +++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts index 05f924d942d..8dd377f0eda 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts @@ -4,9 +4,38 @@ import { KnownWalletNamespaceRpcMethods, KnownWalletRpcMethods, } from '../scope/constants'; -import { getSessionScopes } from './caip-permission-adapter-session-scopes'; +import { + getInternalScopesObject, + getSessionScopes, +} from './caip-permission-adapter-session-scopes'; describe('CAIP-25 session scopes adapters', () => { + describe('getInternalScopesObject', () => { + it('returns an InternalScopesObject with only the accounts from each NormalizedScopeObject', () => { + const result = getInternalScopesObject({ + 'wallet:eip155': { + methods: ['foo', 'bar'], + notifications: ['baz'], + accounts: ['wallet:eip155:0xdead'], + }, + 'eip155:1': { + methods: ['eth_call'], + notifications: ['eth_subscription'], + accounts: ['eip155:1:0xdead', 'eip155:1:0xbeef'], + }, + }); + + expect(result).toStrictEqual({ + 'wallet:eip155': { + accounts: ['wallet:eip155:0xdead'], + }, + 'eip155:1': { + accounts: ['eip155:1:0xdead', 'eip155:1:0xbeef'], + }, + }); + }); + }); + describe('getSessionScopes', () => { it('returns a NormalizedScopesObject for the wallet scope', () => { const result = getSessionScopes({ diff --git a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts index 8de3698bbba..7e05eb01ad3 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.ts @@ -15,6 +15,29 @@ import type { } from '../scope/types'; import { parseScopeString } from '../scope/types'; +/** + * Converts an NormalizedScopesObject to a InternalScopesObject. + * @param normalizedScopesObject - The NormalizedScopesObject to convert. + * @returns An InternalScopesObject. + */ +export const getInternalScopesObject = ( + normalizedScopesObject: NormalizedScopesObject, +) => { + const internalScopes: InternalScopesObject = {}; + + Object.entries(normalizedScopesObject).forEach( + ([_scopeString, { accounts }]) => { + const scopeString = _scopeString as keyof typeof normalizedScopesObject; + + internalScopes[scopeString] = { + accounts, + }; + }, + ); + + return internalScopes; +}; + /** * Converts an InternalScopesObject to a NormalizedScopesObject. * @param internalScopesObject - The InternalScopesObject to convert. diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 654d802d8f0..d7b6fed3826 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -9,6 +9,8 @@ describe('@metamask/multichain', () => { "getPermittedEthChainIds", "addPermittedEthChainId", "setPermittedEthChainIds", + "getInternalScopesObject", + "getSessionScopes", "caipPermissionAdapterMiddleware", "walletGetSession", "walletInvokeMethod", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 0260e269760..f227f2817ae 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -7,6 +7,10 @@ export { addPermittedEthChainId, setPermittedEthChainIds, } from './adapters/caip-permission-adapter-permittedChains'; +export { + getInternalScopesObject, + getSessionScopes, +} from './adapters/caip-permission-adapter-session-scopes'; export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; export { walletGetSession } from './handlers/wallet-getSession'; From 19a5983c4482d2c58f2dccf2f2880e9550e9fbaa Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 22 Nov 2024 08:46:21 -0800 Subject: [PATCH 069/146] Filter out eip1193 only methods from Eip155Methods --- packages/multichain/src/scope/constants.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index 6a9427fd4f0..fc66b28e643 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -28,13 +28,25 @@ export const KnownWalletRpcMethods: string[] = [ const WalletEip155Methods = ['wallet_addEthereumChain']; +const Eip1193OnlyMethods = [ + 'wallet_switchEthereumChain', + 'wallet_getPermissions', + 'wallet_requestPermissions', + 'wallet_revokePermissions', + 'eth_requestAccounts', + 'eth_accounts', + 'eth_coinbase', + 'net_version', +] + /** * All MetaMask methods, except for ones we have specified in the constants above. */ const Eip155Methods = MetaMaskOpenRPCDocument.methods .map(({ name }: { name: string }) => name) .filter((method: string) => !WalletEip155Methods.includes(method)) - .filter((method: string) => !KnownWalletRpcMethods.includes(method)); + .filter((method: string) => !KnownWalletRpcMethods.includes(method)) + .filter((method: string) => !Eip1193OnlyMethods.includes(method)) /** * Methods by ecosystem that are chain specific. From 7d61af678e5ffbf10f4c62ecbfa176df0a140bb9 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 22 Nov 2024 10:31:08 -0800 Subject: [PATCH 070/146] export Eip1193OnlyMethods --- packages/multichain/src/index.test.ts | 1 + packages/multichain/src/index.ts | 1 + packages/multichain/src/scope/constants.test.ts | 7 ------- packages/multichain/src/scope/constants.ts | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index d7b6fed3826..7d929e5f558 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -29,6 +29,7 @@ describe('@metamask/multichain', () => { "KnownWalletNamespaceRpcMethods", "KnownNotifications", "KnownWalletScopeString", + "Eip1193OnlyMethods", "parseScopeString", "isSupportedScopeString", "isSupportedAccount", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index f227f2817ae..e14f0b2e478 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -34,6 +34,7 @@ export { KnownWalletNamespaceRpcMethods, KnownNotifications, KnownWalletScopeString, + Eip1193OnlyMethods, } from './scope/constants'; export type { ExternalScopeString, diff --git a/packages/multichain/src/scope/constants.test.ts b/packages/multichain/src/scope/constants.test.ts index 8369ec721a9..362bead5a77 100644 --- a/packages/multichain/src/scope/constants.test.ts +++ b/packages/multichain/src/scope/constants.test.ts @@ -6,15 +6,9 @@ describe('KnownRpcMethods', () => { Object { "bip122": Array [], "eip155": Array [ - "wallet_switchEthereumChain", - "wallet_getPermissions", - "wallet_requestPermissions", - "wallet_revokePermissions", "personal_sign", "eth_signTypedData_v4", "wallet_watchAsset", - "eth_requestAccounts", - "eth_accounts", "eth_sendTransaction", "eth_decrypt", "eth_getEncryptionPublicKey", @@ -24,7 +18,6 @@ describe('KnownRpcMethods', () => { "eth_blockNumber", "eth_call", "eth_chainId", - "eth_coinbase", "eth_estimateGas", "eth_feeHistory", "eth_gasPrice", diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index fc66b28e643..1f9400c8929 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -28,7 +28,7 @@ export const KnownWalletRpcMethods: string[] = [ const WalletEip155Methods = ['wallet_addEthereumChain']; -const Eip1193OnlyMethods = [ +export const Eip1193OnlyMethods = [ 'wallet_switchEthereumChain', 'wallet_getPermissions', 'wallet_requestPermissions', From 97b4a095f89b71370bb378d2a6a370eaa9550fb2 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 22 Nov 2024 10:37:25 -0800 Subject: [PATCH 071/146] Revert "export Eip1193OnlyMethods" This reverts commit 7d61af678e5ffbf10f4c62ecbfa176df0a140bb9. --- packages/multichain/src/index.test.ts | 1 - packages/multichain/src/index.ts | 1 - packages/multichain/src/scope/constants.test.ts | 7 +++++++ packages/multichain/src/scope/constants.ts | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 7d929e5f558..d7b6fed3826 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -29,7 +29,6 @@ describe('@metamask/multichain', () => { "KnownWalletNamespaceRpcMethods", "KnownNotifications", "KnownWalletScopeString", - "Eip1193OnlyMethods", "parseScopeString", "isSupportedScopeString", "isSupportedAccount", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index e14f0b2e478..f227f2817ae 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -34,7 +34,6 @@ export { KnownWalletNamespaceRpcMethods, KnownNotifications, KnownWalletScopeString, - Eip1193OnlyMethods, } from './scope/constants'; export type { ExternalScopeString, diff --git a/packages/multichain/src/scope/constants.test.ts b/packages/multichain/src/scope/constants.test.ts index 362bead5a77..8369ec721a9 100644 --- a/packages/multichain/src/scope/constants.test.ts +++ b/packages/multichain/src/scope/constants.test.ts @@ -6,9 +6,15 @@ describe('KnownRpcMethods', () => { Object { "bip122": Array [], "eip155": Array [ + "wallet_switchEthereumChain", + "wallet_getPermissions", + "wallet_requestPermissions", + "wallet_revokePermissions", "personal_sign", "eth_signTypedData_v4", "wallet_watchAsset", + "eth_requestAccounts", + "eth_accounts", "eth_sendTransaction", "eth_decrypt", "eth_getEncryptionPublicKey", @@ -18,6 +24,7 @@ describe('KnownRpcMethods', () => { "eth_blockNumber", "eth_call", "eth_chainId", + "eth_coinbase", "eth_estimateGas", "eth_feeHistory", "eth_gasPrice", diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index 1f9400c8929..fc66b28e643 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -28,7 +28,7 @@ export const KnownWalletRpcMethods: string[] = [ const WalletEip155Methods = ['wallet_addEthereumChain']; -export const Eip1193OnlyMethods = [ +const Eip1193OnlyMethods = [ 'wallet_switchEthereumChain', 'wallet_getPermissions', 'wallet_requestPermissions', From 6732cd9ae6774395cf9cc46e107decde53aea3b3 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 22 Nov 2024 10:38:55 -0800 Subject: [PATCH 072/146] use Eip1193OnlyMethods in adapter middleware --- .../src/adapters/caip-permission-adapter-middleware.ts | 5 +++-- packages/multichain/src/scope/constants.ts | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 12402b17f9f..89b47e8f81b 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -11,7 +11,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { KnownWalletScopeString } from '../scope/constants'; +import { Eip1193OnlyMethods, KnownWalletScopeString } from '../scope/constants'; import type { InternalScopeString } from '../scope/types'; import { getSessionScopes } from './caip-permission-adapter-session-scopes'; @@ -69,7 +69,8 @@ export async function caipPermissionAdapterMiddleware( if ( !sesionScopes[scope]?.methods?.includes(method) && !sesionScopes[KnownWalletScopeString.Eip155]?.methods?.includes(method) && - !sesionScopes.wallet?.methods?.includes(method) + !sesionScopes.wallet?.methods?.includes(method) && + !Eip1193OnlyMethods.includes(method) ) { return end(providerErrors.unauthorized()); } diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index fc66b28e643..c121aeeff7b 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -28,7 +28,7 @@ export const KnownWalletRpcMethods: string[] = [ const WalletEip155Methods = ['wallet_addEthereumChain']; -const Eip1193OnlyMethods = [ +export const Eip1193OnlyMethods = [ 'wallet_switchEthereumChain', 'wallet_getPermissions', 'wallet_requestPermissions', @@ -37,7 +37,7 @@ const Eip1193OnlyMethods = [ 'eth_accounts', 'eth_coinbase', 'net_version', -] +]; /** * All MetaMask methods, except for ones we have specified in the constants above. @@ -46,7 +46,7 @@ const Eip155Methods = MetaMaskOpenRPCDocument.methods .map(({ name }: { name: string }) => name) .filter((method: string) => !WalletEip155Methods.includes(method)) .filter((method: string) => !KnownWalletRpcMethods.includes(method)) - .filter((method: string) => !Eip1193OnlyMethods.includes(method)) + .filter((method: string) => !Eip1193OnlyMethods.includes(method)); /** * Methods by ecosystem that are chain specific. From e03033c83610ba0371b665fc16555b59831234a0 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 22 Nov 2024 10:58:31 -0800 Subject: [PATCH 073/146] expand Eip1193OnlyMethods to include meta methods --- packages/multichain/src/scope/constants.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index c121aeeff7b..ea1291f7b92 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -37,6 +37,10 @@ export const Eip1193OnlyMethods = [ 'eth_accounts', 'eth_coinbase', 'net_version', + 'metamask_logWeb3ShimUsage', + 'metamask_getProviderState', + 'metamask_sendDomainMetadata', + 'wallet_registerOnboarding', ]; /** From e1793ff003e960530bd4c8d30ffd30d749094933 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 10:57:35 -0600 Subject: [PATCH 074/146] cleanup + add tests for MultichainSubscriptionManager --- .../MultichainSubscriptionManager.test.ts | 40 +++++++++++++++++++ .../MultichainSubscriptionManager.ts | 15 +++---- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index cf05aa5c5a9..f08182d0263 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -63,6 +63,26 @@ describe('MultichainSubscriptionManager', () => { MockCreateSubscriptionManager.mockReturnValue(mockSubscriptionManager); }); + it('should not create a new subscriptionManager if one matches the passed in subscriptionKey', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + + const firstSubscription = multichainSubscriptionManager.subscribe({ + scope, + origin, + tabId, + }); + + const secondSubscription = multichainSubscriptionManager.subscribe({ + scope, + origin, + tabId, + }); + + expect(secondSubscription).toBe(firstSubscription); + expect(MockCreateSubscriptionManager).toHaveBeenCalledTimes(1); + }); + it('should subscribe to a scope, origin, and tabId', () => { const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); @@ -105,6 +125,26 @@ describe('MultichainSubscriptionManager', () => { expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); + it('should do nothing if an unsubscribe call does not match an existing subscription', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + multichainSubscriptionManager.unsubscribeByScope('eip155:10'); + multichainSubscriptionManager.unsubscribeByScopeAndOrigin( + scope, + 'other-origin', + ); + multichainSubscriptionManager.unsubscribeByOriginAndTabId( + 'other-origin', + 123, + ); + mockSubscriptionManager.events.on.mock.calls[0][1]( + newHeadsNotificationMock, + ); + + expect(mockSubscriptionManager.destroy).not.toHaveBeenCalled(); + }); + it('should unsubscribe from a origin and tabId', () => { const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 6494ed24a59..e3b9cbfb76c 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -76,7 +76,7 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { }); } - #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionKey) { + #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionEntry) { this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => { return ( subscriptionEntry.scope !== scope || @@ -116,16 +116,10 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { return subscriptionManager; } - #unsubscribe(subscriptionKey: SubscriptionKey) { - const existingSubscriptionEntry = - this.#getSubscriptionEntry(subscriptionKey); - if (!existingSubscriptionEntry) { - return; - } - - existingSubscriptionEntry.subscriptionManager.destroy?.(); + #unsubscribe(subscriptionEntry: SubscriptionEntry) { + subscriptionEntry.subscriptionManager.destroy?.(); - this.#removeSubscriptionEntry(subscriptionKey); + this.#removeSubscriptionEntry(subscriptionEntry); } unsubscribeByScope(scope: ExternalScopeString) { @@ -137,6 +131,7 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { } unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) { + console.log('unsubscribing by scope and origin', scope, origin); this.#subscriptions.forEach((subscriptionEntry) => { if ( subscriptionEntry.scope === scope && From 4c9be0e0d823dd16a1e200314330aa39f24d4166 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 14:08:02 -0600 Subject: [PATCH 075/146] adding tests for multichainMethodCallValidator --- .../multichainMethodCallValidator.test.ts | 411 ++++++++++++++++++ .../multichainMethodCallValidator.ts | 28 +- .../multichain/src/scope/constants.test.ts | 7 - packages/multichain/src/scope/types.ts | 58 +++ 4 files changed, 496 insertions(+), 8 deletions(-) create mode 100644 packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts new file mode 100644 index 00000000000..c7e9a89d991 --- /dev/null +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -0,0 +1,411 @@ +import type { + JsonRpcError, + JsonRpcRequest, + JsonRpcResponse, +} from '@metamask/utils'; + +import type { + Caip27Params, + Caip285Params, + Caip319Params, +} from '../scope/types'; +import { multichainMethodCallValidatorMiddleware } from './multichainMethodCallValidator'; + +describe('multichainMethodCallValidatorMiddleware', () => { + const mockNext = jest.fn(); + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('"wallet_invokeMethod" request', () => { + it('should pass validation for a "wallet_invokeMethod" request and call next', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'wallet_invokeMethod', + params: { + scope: 'test', + request: { + method: 'test_method', + params: { + test: 'test', + }, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + reject(error); + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + it('should throw an error for a a "wallet_invokeMethod" request with no scope', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'wallet_invokeMethod', + // @ts-expect-error test + params: { + request: { + method: 'test_method', + params: { + test: 'test', + }, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).data).toStrictEqual([ + { + code: -32602, + message: 'scope is required, but is undefined', + data: { + param: 'scope', + path: [], + schema: { + pattern: '[-a-z0-9]{3,8}(:[-_a-zA-Z0-9]{1,32})?', + type: 'string', + }, + got: undefined, + }, + }, + ]); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + it('should throw an error for a "wallet_invokeMethod" request without a nested request object', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'wallet_invokeMethod', + // @ts-expect-error test + params: { + scope: 'test', + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).data).toStrictEqual([ + { + code: -32602, + data: { + got: undefined, + param: 'request', + path: [], + schema: { + properties: { + method: { + type: 'string', + }, + params: true, + }, + type: 'object', + }, + }, + message: 'request is required, but is undefined', + }, + ]); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + }); + + describe('"wallet_notify" request', () => { + it('should pass validation for a "wallet_notify" request and call next', async () => { + const request: JsonRpcRequest = { + id: 2, + jsonrpc: '2.0', + method: 'wallet_notify', + params: { + scope: 'test_scope', + notification: { + method: 'test_method', + params: { + data: { + key: 'value', + }, + }, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + reject(error); + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + + it('should throw an error for a "wallet_notify" request with invalid params', async () => { + const request: JsonRpcRequest = { + id: 2, + jsonrpc: '2.0', + method: 'wallet_notify', + params: { + // Missing required parameters or invalid structure + scope: 'test_scope', + request: { + // @ts-expect-error test + event: '', + data: {}, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + expect((error as JsonRpcError).data).toStrictEqual([ + { + code: -32602, + data: { + got: undefined, + param: 'notification', + path: [], + schema: { + properties: { + method: { + type: 'string', + }, + params: true, + }, + type: 'object', + }, + }, + message: 'notification is required, but is undefined', + }, + ]); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + }); + + describe('"wallet_revokeSession" request', () => { + it('should pass validation for a "wallet_revokeSession" request and call next', async () => { + const request: JsonRpcRequest = { + id: 3, + jsonrpc: '2.0', + method: 'wallet_revokeSession', + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + reject(error); + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + }); + + describe('"wallet_getSession" request', () => { + it('should pass validation for a "wallet_getSession" request and call next', async () => { + const request: JsonRpcRequest = { + id: 5, + jsonrpc: '2.0', + method: 'wallet_getSession', + // @ts-expect-error TODO figure out why this type is not working + params: {}, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + reject(error); + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + }); + + it('should throw an error is passed an unknown method', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'unknown_method', + // @ts-expect-error test + params: { + request: { + method: 'test_method', + params: { + test: 'test', + }, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + console.log('error in test', error); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).data).toStrictEqual([ + { + code: -32601, + message: 'The method does not exist / is not available.', + data: { + method: 'unknown_method', + }, + }, + ]); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); +}); diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index cc075140e28..7748957bf00 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -18,6 +18,8 @@ import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-r import type { Schema, ValidationError } from 'jsonschema'; import { Validator } from 'jsonschema'; +import type { Caip27Params, Caip285Params, Caip319Params } from '../scope/types'; + const transformError = ( error: ValidationError, param: ContentDescriptorObject, @@ -54,10 +56,28 @@ const multichainMethodCallValidator = async ( const methodToCheck = dereffed.methods.find( (m) => (m as unknown as ContentDescriptorObject).name === method, ); + const errors: JsonRpcError[] = []; + if ( + !methodToCheck || + !isObject(methodToCheck) || + !('params' in methodToCheck) + ) { + return [ + { + code: -32601, + message: 'The method does not exist / is not available.', + data: { + method, + }, + }, + ]; + } + // check each param and aggregate errors (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { let paramToCheck: Json | undefined; + console.log('param', param); const p = param as ContentDescriptorObject; if (isObject(params)) { paramToCheck = params[p.name]; @@ -66,6 +86,8 @@ const multichainMethodCallValidator = async ( } else { paramToCheck = undefined; } + console.log('paramToCheck', paramToCheck); + console.log('p.schema', p.schema); const result = v.validate(paramToCheck, p.schema as unknown as Schema, { required: p.required, }); @@ -77,22 +99,26 @@ const multichainMethodCallValidator = async ( ); } }); + console.log('errors', errors); if (errors.length > 0) { return errors; } + console.log('no errors'); // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors // would be an array and return true if it's empty return false; }; export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< - JsonRpcRequest, + JsonRpcRequest | Caip27Params | Caip319Params | Caip285Params, Json > = function (request, _response, next, end) { // eslint-disable-next-line @typescript-eslint/no-floating-promises multichainMethodCallValidator(request.method, request.params).then( (errors) => { + console.log('errors', errors); if (errors) { + console.log('errors', errors); return end(rpcErrors.invalidParams({ data: errors })); } return next(); diff --git a/packages/multichain/src/scope/constants.test.ts b/packages/multichain/src/scope/constants.test.ts index 8369ec721a9..362bead5a77 100644 --- a/packages/multichain/src/scope/constants.test.ts +++ b/packages/multichain/src/scope/constants.test.ts @@ -6,15 +6,9 @@ describe('KnownRpcMethods', () => { Object { "bip122": Array [], "eip155": Array [ - "wallet_switchEthereumChain", - "wallet_getPermissions", - "wallet_requestPermissions", - "wallet_revokePermissions", "personal_sign", "eth_signTypedData_v4", "wallet_watchAsset", - "eth_requestAccounts", - "eth_accounts", "eth_sendTransaction", "eth_decrypt", "eth_getEncryptionPublicKey", @@ -24,7 +18,6 @@ describe('KnownRpcMethods', () => { "eth_blockNumber", "eth_call", "eth_chainId", - "eth_coinbase", "eth_estimateGas", "eth_feeHistory", "eth_gasPrice", diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index b13b5edae75..c5bc5e7a15e 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -10,6 +10,8 @@ import type { KnownCaipNamespace, CaipNamespace, Json, + JsonRpcRequest, + JsonRpcParams, } from '@metamask/utils'; /** @@ -119,3 +121,59 @@ export type NonWalletKnownCaipNamespace = Exclude< KnownCaipNamespace, KnownCaipNamespace.Wallet >; + +// { +// "id": 1, +// "jsonrpc": "2.0", +// "method": "wallet_invokeMethod", +// "params": { +// "sessionId": "0xdeadbeef", +// "scope": "eip155:1", +// "request": { +// "method": "eth_sendTransaction", +// "params": [ +// { +// "to": "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7", +// "from": "0xDeaDbeefdEAdbeefdEadbEEFdeadbeefDEADbEEF", +// "gas": "0x76c0", +// "value": "0x8ac7230489e80000", +// "data": "0x", +// "gasPrice": "0x4a817c800" +// } +// ] +// } +// } +// } + +/** + * Parameters for the `wallet_invokeMethod` method as defined in CAIP-27. + */ +export type Caip27Params = { + scope: string; + request: { + method: string; + params: JsonRpcParams; + }; +}; + +/** + * Parameters for the `wallet_notify` method as defined in CAIP-319. + */ +export type Caip319Params = { + scope: string; + notification: { + method: string; + params: JsonRpcParams; + }; +}; + +/** + * Parameters for the `wallet_revokeSession` method as defined in CAIP-285. + */ +export type Caip285Params = { + scope: string; + request: { + method: string; + params: Record; + }; +}; From a25c05d11dbc3761dd8799d692e6619f2a7dd229 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 15:28:18 -0600 Subject: [PATCH 076/146] cleanup --- .../middlewares/multichainMethodCallValidator.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index 7748957bf00..badafa80999 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -18,7 +18,11 @@ import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-r import type { Schema, ValidationError } from 'jsonschema'; import { Validator } from 'jsonschema'; -import type { Caip27Params, Caip285Params, Caip319Params } from '../scope/types'; +import type { + Caip27Params, + Caip285Params, + Caip319Params, +} from '../scope/types'; const transformError = ( error: ValidationError, @@ -77,7 +81,6 @@ const multichainMethodCallValidator = async ( // check each param and aggregate errors (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { let paramToCheck: Json | undefined; - console.log('param', param); const p = param as ContentDescriptorObject; if (isObject(params)) { paramToCheck = params[p.name]; @@ -86,8 +89,6 @@ const multichainMethodCallValidator = async ( } else { paramToCheck = undefined; } - console.log('paramToCheck', paramToCheck); - console.log('p.schema', p.schema); const result = v.validate(paramToCheck, p.schema as unknown as Schema, { required: p.required, }); @@ -99,11 +100,9 @@ const multichainMethodCallValidator = async ( ); } }); - console.log('errors', errors); if (errors.length > 0) { return errors; } - console.log('no errors'); // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors // would be an array and return true if it's empty return false; @@ -116,9 +115,7 @@ export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< // eslint-disable-next-line @typescript-eslint/no-floating-promises multichainMethodCallValidator(request.method, request.params).then( (errors) => { - console.log('errors', errors); if (errors) { - console.log('errors', errors); return end(rpcErrors.invalidParams({ data: errors })); } return next(); From b35bdc369a979e15db5e18e35c69e75428430201 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 15:36:20 -0600 Subject: [PATCH 077/146] lint --- packages/multichain/src/scope/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index c5bc5e7a15e..4d426be6a15 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -10,7 +10,6 @@ import type { KnownCaipNamespace, CaipNamespace, Json, - JsonRpcRequest, JsonRpcParams, } from '@metamask/utils'; From 2ad05a38ac3221841e4508896a274088e11c3dae Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 16:03:41 -0600 Subject: [PATCH 078/146] question --- .../src/middlewares/multichainMethodCallValidator.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index badafa80999..e96d6fdeafc 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -57,6 +57,7 @@ const multichainMethodCallValidator = async ( params: JsonRpcParams | undefined, ) => { const dereffed = await dereffedPromise; + const methodToCheck = dereffed.methods.find( (m) => (m as unknown as ContentDescriptorObject).name === method, ); @@ -77,13 +78,13 @@ const multichainMethodCallValidator = async ( }, ]; } - // check each param and aggregate errors (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { let paramToCheck: Json | undefined; const p = param as ContentDescriptorObject; if (isObject(params)) { paramToCheck = params[p.name]; + // TODO: according to the spec all of the multichain method params are objects, should this be removed? } else if (params && Array.isArray(params)) { paramToCheck = params[i]; } else { From 79acd26d2f538e8caad2511f68b4edb7ad246b88 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 16:18:41 -0600 Subject: [PATCH 079/146] small cleanup --- .../multichainMethodCallValidator.test.ts | 16 +++++++--------- .../middlewares/multichainMethodCallValidator.ts | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index c7e9a89d991..f022e0c8262 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -18,7 +18,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); describe('"wallet_invokeMethod" request', () => { - it('should pass validation for a "wallet_invokeMethod" request and call next', async () => { + it('should pass validation and call next when passed a valid "wallet_invokeMethod" request', async () => { const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', @@ -55,7 +55,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); }); - it('should throw an error for a a "wallet_invokeMethod" request with no scope', async () => { + it('should throw an error when passed a "wallet_invokeMethod" request with no scope', async () => { const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', @@ -221,16 +221,14 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); it('should throw an error for a "wallet_notify" request with invalid params', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 2, jsonrpc: '2.0', method: 'wallet_notify', + // @ts-expect-error test params: { - // Missing required parameters or invalid structure scope: 'test_scope', request: { - // @ts-expect-error test - event: '', data: {}, }, }, @@ -289,7 +287,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); describe('"wallet_revokeSession" request', () => { - it('should pass validation for a "wallet_revokeSession" request and call next', async () => { + it('should pass validation and call next when passed a valid "wallet_revokeSession" request', async () => { const request: JsonRpcRequest = { id: 3, jsonrpc: '2.0', @@ -320,7 +318,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); describe('"wallet_getSession" request', () => { - it('should pass validation for a "wallet_getSession" request and call next', async () => { + it('should pass validation and call next when passed a valid "wallet_getSession" request', async () => { const request: JsonRpcRequest = { id: 5, jsonrpc: '2.0', @@ -352,7 +350,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); - it('should throw an error is passed an unknown method', async () => { + it('should throw an error when passed an unknown method', async () => { const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index e96d6fdeafc..a3e3337f674 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -84,7 +84,7 @@ const multichainMethodCallValidator = async ( const p = param as ContentDescriptorObject; if (isObject(params)) { paramToCheck = params[p.name]; - // TODO: according to the spec all of the multichain method params are objects, should this be removed? + // TODO: according to the spec all of the multichain method params values should be objects, should this be removed? } else if (params && Array.isArray(params)) { paramToCheck = params[i]; } else { From 32aa80736ec13a17e47757376fb9098e74b61251 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 22 Nov 2024 16:51:25 -0600 Subject: [PATCH 080/146] more cleanup --- .../multichainMethodCallValidator.test.ts | 42 ++++++++++++++++++- .../multichainMethodCallValidator.ts | 18 ++++---- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index f022e0c8262..14903fe7d07 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -350,7 +350,47 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); - it('should throw an error when passed an unknown method', async () => { + it('should throw an error if the top level params are not an object', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'wallet_invokeMethod', + // @ts-expect-error test + params: ['test'], + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + + it('should throw an error when passed an unknown method at the top level', async () => { const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index a3e3337f674..edd9a0fda2e 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -79,17 +79,17 @@ const multichainMethodCallValidator = async ( ]; } // check each param and aggregate errors - (methodToCheck as unknown as MethodObject).params.forEach((param, i) => { - let paramToCheck: Json | undefined; + (methodToCheck as unknown as MethodObject).params.forEach((param) => { const p = param as ContentDescriptorObject; - if (isObject(params)) { - paramToCheck = params[p.name]; - // TODO: according to the spec all of the multichain method params values should be objects, should this be removed? - } else if (params && Array.isArray(params)) { - paramToCheck = params[i]; - } else { - paramToCheck = undefined; + if (!isObject(params)) { + errors.push({ + code: -32602, + message: 'Invalid method parameter(s).', + }); + return; } + const paramToCheck = params[p.name]; + const result = v.validate(paramToCheck, p.schema as unknown as Schema, { required: p.required, }); From 121ba943286fd3649c274eff6a5d6ee185270ad3 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 25 Nov 2024 15:39:12 -0600 Subject: [PATCH 081/146] remove lingering console --- .../multichain/src/middlewares/MultichainSubscriptionManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index e3b9cbfb76c..9a2259e2d32 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -131,7 +131,6 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { } unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) { - console.log('unsubscribing by scope and origin', scope, origin); this.#subscriptions.forEach((subscriptionEntry) => { if ( subscriptionEntry.scope === scope && From 6d4bd0400718481dd60bc5cb645520f22e807a5b Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Tue, 26 Nov 2024 09:42:13 -0600 Subject: [PATCH 082/146] this seems like a reasonable tweak (#4980) Not sure if I'm missing something about why we were refetching the middleware after passing in the whole entry...? --- .../src/middlewares/MultichainMiddlewareManager.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index d1e52f93852..32109a8c569 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -46,7 +46,7 @@ export class MultichainMiddlewareManager { }); } - #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareKey) { + #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareEntry) { this.#middlewares = this.#middlewares.filter((middlewareEntry) => { return ( middlewareEntry.scope !== scope || @@ -63,18 +63,13 @@ export class MultichainMiddlewareManager { } } - #removeMiddleware(middlewareKey: MiddlewareKey) { - const existingMiddlewareEntry = this.#getMiddlewareEntry(middlewareKey); - if (!existingMiddlewareEntry) { - return; - } - + #removeMiddleware(middlewareEntry: MiddlewareEntry) { // When the destroy function on the middleware is async, // we don't need to wait for it complete // eslint-disable-next-line no-void - void existingMiddlewareEntry.middleware.destroy?.(); + void middlewareEntry.middleware.destroy?.(); - this.#removeMiddlewareEntry(middlewareKey); + this.#removeMiddlewareEntry(middlewareEntry); } removeMiddlewareByScope(scope: ExternalScopeString) { From 5a621b37094ca65e01ed6ccea24e10997554872d Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 26 Nov 2024 10:33:22 -0600 Subject: [PATCH 083/146] 100% test coverage --- .../multichainMethodCallValidator.test.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index 14903fe7d07..f951c26e9ba 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -167,6 +167,72 @@ describe('multichainMethodCallValidatorMiddleware', () => { }, ); + process.nextTick(() => { + try { + expect(mockNext).not.toHaveBeenCalled(); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }); + it('should throw an error for an invalidly formatted "wallet_invokeMethod" request', async () => { + const request: JsonRpcRequest = { + id: 1, + jsonrpc: '2.0', + method: 'wallet_invokeMethod', + // @ts-expect-error test + params: { + scope: 'test', + request: { + method: {}, // expected to be a string + params: { + test: 'test', + }, + }, + }, + }; + const response = {} as JsonRpcResponse; + + await new Promise((resolve, reject) => { + multichainMethodCallValidatorMiddleware( + request, + response, + mockNext, + (error) => { + try { + expect(error).toBeDefined(); + expect((error as JsonRpcError).message).toBe( + 'Invalid method parameter(s).', + ); + expect((error as JsonRpcError).code).toBe(-32602); + expect((error as JsonRpcError).data).toStrictEqual([ + { + code: -32602, + data: { + got: { + method: {}, + params: { + test: 'test', + }, + }, + param: 'request', + path: ['method'], + schema: { + type: 'string', + }, + }, + message: 'request.method is not of a type(s) string', + }, + ]); + resolve(); + } catch (e) { + reject(e); + } + }, + ); + process.nextTick(() => { try { expect(mockNext).not.toHaveBeenCalled(); From 57e6ab5dce37256db339f4883312208505a4b3f1 Mon Sep 17 00:00:00 2001 From: jiexi Date: Mon, 2 Dec 2024 12:16:51 -0800 Subject: [PATCH 084/146] Override subscriptionManager.middleware.destroy to also remove sub entry (#4984) ## Explanation Ensures that the subscription entry for a subscription is removed when the middleware is destroyed ## References Related: https://github.com/MetaMask/metamask-extension/pull/28751 ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- .../MultichainSubscriptionManager.test.ts | 37 +++++++++++-------- .../MultichainSubscriptionManager.ts | 16 ++++++-- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index f08182d0263..010effb025f 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -1,4 +1,5 @@ import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; +import type SafeEventEmitter from '@metamask/safe-event-emitter'; import { MultichainSubscriptionManager } from './MultichainSubscriptionManager'; @@ -51,15 +52,21 @@ const createMultichainSubscriptionManager = () => { return { multichainSubscriptionManager }; }; -describe('MultichainSubscriptionManager', () => { - const mockSubscriptionManager = { - events: { - on: jest.fn(), - }, +const createMockSubscriptionManager = () => ({ + events: { + on: jest.fn(), + } as unknown as jest.Mocked, + destroy: jest.fn(), + middleware: { destroy: jest.fn(), - }; + }, +}); + +describe('MultichainSubscriptionManager', () => { + let mockSubscriptionManager = createMockSubscriptionManager(); beforeEach(() => { + mockSubscriptionManager = createMockSubscriptionManager(); MockCreateSubscriptionManager.mockReturnValue(mockSubscriptionManager); }); @@ -118,10 +125,6 @@ describe('MultichainSubscriptionManager', () => { multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByScopeAndOrigin(scope, origin); - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); - expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); @@ -138,9 +141,6 @@ describe('MultichainSubscriptionManager', () => { 'other-origin', 123, ); - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); expect(mockSubscriptionManager.destroy).not.toHaveBeenCalled(); }); @@ -151,9 +151,14 @@ describe('MultichainSubscriptionManager', () => { multichainSubscriptionManager.subscribe({ scope, origin, tabId }); multichainSubscriptionManager.unsubscribeByOriginAndTabId(origin, tabId); - mockSubscriptionManager.events.on.mock.calls[0][1]( - newHeadsNotificationMock, - ); + expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); + }); + + it('should unsubscribe when the middleware is destroyed', () => { + const { multichainSubscriptionManager } = + createMultichainSubscriptionManager(); + multichainSubscriptionManager.subscribe({ scope, origin, tabId }); + mockSubscriptionManager.middleware.destroy(); expect(mockSubscriptionManager.destroy).toHaveBeenCalled(); }); diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 9a2259e2d32..22e92705247 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -4,13 +4,14 @@ import type { NetworkController } from '@metamask/network-controller'; import SafeEventEmitter from '@metamask/safe-event-emitter'; import type { CaipChainId, Hex } from '@metamask/utils'; import { parseCaipChainId } from '@metamask/utils'; -import type EventEmitter from 'events'; import type { ExternalScopeString } from '../scope/types'; +import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; export type SubscriptionManager = { - events: EventEmitter; + events: SafeEventEmitter; destroy?: () => void; + middleware: ExtendedJsonRpcMiddleware; }; type SubscriptionNotificationEvent = { @@ -108,10 +109,17 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { }, ); - this.#subscriptions.push({ + const newSubscriptionManagerEntry = { ...subscriptionKey, subscriptionManager, - }); + }; + subscriptionManager.destroy = subscriptionManager.middleware.destroy; + subscriptionManager.middleware.destroy = this.#unsubscribe.bind( + this, + newSubscriptionManagerEntry, + ); + + this.#subscriptions.push(newSubscriptionManagerEntry); return subscriptionManager; } From 1ec9503f82605bc6b0c10ff307ff9fd92242fbbc Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 12:43:59 -0800 Subject: [PATCH 085/146] stop exporting unused helpers --- packages/multichain/src/index.test.ts | 6 ------ packages/multichain/src/index.ts | 9 --------- 2 files changed, 15 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index d7b6fed3826..a1695dc677d 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -30,16 +30,10 @@ describe('@metamask/multichain', () => { "KnownNotifications", "KnownWalletScopeString", "parseScopeString", - "isSupportedScopeString", - "isSupportedAccount", - "isSupportedMethod", - "isSupportedNotification", "normalizeScope", "mergeScopeObject", "mergeScopes", "normalizeAndMergeScopes", - "isValidScope", - "getValidScopes", "Caip25CaveatType", "createCaip25Caveat", "Caip25EndowmentPermissionName", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index f227f2817ae..bfc48f54bb5 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -48,21 +48,12 @@ export type { NonWalletKnownCaipNamespace, } from './scope/types'; export { parseScopeString } from './scope/types'; -// Do these need to be exported? -export { - isSupportedScopeString, - isSupportedAccount, - isSupportedMethod, - isSupportedNotification, -} from './scope/supported'; export { normalizeScope, mergeScopeObject, mergeScopes, normalizeAndMergeScopes, } from './scope/transform'; -// does this need to be exported? -export { isValidScope, getValidScopes } from './scope/validation'; export type { Caip25CaveatValue } from './caip25Permission'; export { From 02144d1dc688cd75f500028beaa0a2d61f267cf5 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 13:02:02 -0800 Subject: [PATCH 086/146] remove more unused exports --- packages/multichain/src/index.test.ts | 2 -- packages/multichain/src/index.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index a1695dc677d..df981a7ec5b 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -18,8 +18,6 @@ describe('@metamask/multichain', () => { "multichainMethodCallValidatorMiddleware", "MultichainMiddlewareManager", "MultichainSubscriptionManager", - "assertScopeSupported", - "assertScopesSupported", "validateAndNormalizeScopes", "bucketScopes", "bucketScopesBySupport", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index bfc48f54bb5..8cf0f3ba570 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -21,7 +21,6 @@ export { multichainMethodCallValidatorMiddleware } from './middlewares/multichai export { MultichainMiddlewareManager } from './middlewares/MultichainMiddlewareManager'; export { MultichainSubscriptionManager } from './middlewares/MultichainSubscriptionManager'; -export { assertScopeSupported, assertScopesSupported } from './scope/assert'; export type { Caip25Authorization } from './scope/authorization'; export { validateAndNormalizeScopes, From 78737cbe4b69e1049ae323914a28870d5bed91c4 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 13:02:48 -0800 Subject: [PATCH 087/146] remove more unused exports --- packages/multichain/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 8cf0f3ba570..c7fbf580d14 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -26,7 +26,6 @@ export { validateAndNormalizeScopes, bucketScopes, } from './scope/authorization'; -export { bucketScopesBySupport, filterScopesSupported } from './scope/filter'; export { KnownWalletRpcMethods, KnownRpcMethods, From f8ca8982a7581db931bf6175c4b142fbf72da030 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 13:07:30 -0800 Subject: [PATCH 088/146] fix snapshot --- packages/multichain/src/index.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index df981a7ec5b..d60cd75f138 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -20,8 +20,6 @@ describe('@metamask/multichain', () => { "MultichainSubscriptionManager", "validateAndNormalizeScopes", "bucketScopes", - "bucketScopesBySupport", - "filterScopesSupported", "KnownWalletRpcMethods", "KnownRpcMethods", "KnownWalletNamespaceRpcMethods", From e8b2487972b5e3237ae450152e25395e6d06aac4 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 13:24:01 -0800 Subject: [PATCH 089/146] align json-schema version --- packages/multichain/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 4d8e8a9ff76..79f8f94a85d 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -54,7 +54,7 @@ "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^10.0.0", "@open-rpc/schema-utils-js": "^2.0.5", - "jsonschema": "^1.2.4", + "jsonschema": "^1.4.1", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 53047fdb147..d100253d941 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3121,7 +3121,7 @@ __metadata: "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" - jsonschema: "npm:^1.2.4" + jsonschema: "npm:^1.4.1" lodash: "npm:^4.17.21" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" @@ -9625,7 +9625,7 @@ __metadata: languageName: node linkType: hard -"jsonschema@npm:^1.2.4, jsonschema@npm:^1.4.1": +"jsonschema@npm:^1.4.1": version: 1.4.1 resolution: "jsonschema@npm:1.4.1" checksum: 10/d7a188da7a3100a2caa362b80e98666d46607b7a7153aac405b8e758132961911c6df02d444d4700691330874e21a62639f550e856b21ddd28423690751ca9c6 From 9cfbf21f7e01d79917ccdf7140c3b50f230af5ba Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 5 Dec 2024 14:04:04 -0800 Subject: [PATCH 090/146] remove caip lifecycle method param types (#5031) ## Explanation ## References ## Changelog ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- .../multichainMethodCallValidator.test.ts | 32 ++++------- .../multichainMethodCallValidator.ts | 15 +---- packages/multichain/src/scope/types.ts | 57 ------------------- 3 files changed, 12 insertions(+), 92 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index f951c26e9ba..cc10661aa27 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -4,11 +4,6 @@ import type { JsonRpcResponse, } from '@metamask/utils'; -import type { - Caip27Params, - Caip285Params, - Caip319Params, -} from '../scope/types'; import { multichainMethodCallValidatorMiddleware } from './multichainMethodCallValidator'; describe('multichainMethodCallValidatorMiddleware', () => { @@ -19,7 +14,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { describe('"wallet_invokeMethod" request', () => { it('should pass validation and call next when passed a valid "wallet_invokeMethod" request', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'wallet_invokeMethod', @@ -56,11 +51,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); it('should throw an error when passed a "wallet_invokeMethod" request with no scope', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'wallet_invokeMethod', - // @ts-expect-error test params: { request: { method: 'test_method', @@ -117,11 +111,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); it('should throw an error for a "wallet_invokeMethod" request without a nested request object', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'wallet_invokeMethod', - // @ts-expect-error test params: { scope: 'test', }, @@ -178,11 +171,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); }); it('should throw an error for an invalidly formatted "wallet_invokeMethod" request', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'wallet_invokeMethod', - // @ts-expect-error test params: { scope: 'test', request: { @@ -247,7 +239,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { describe('"wallet_notify" request', () => { it('should pass validation for a "wallet_notify" request and call next', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 2, jsonrpc: '2.0', method: 'wallet_notify', @@ -287,11 +279,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); it('should throw an error for a "wallet_notify" request with invalid params', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 2, jsonrpc: '2.0', method: 'wallet_notify', - // @ts-expect-error test params: { scope: 'test_scope', request: { @@ -354,7 +345,7 @@ describe('multichainMethodCallValidatorMiddleware', () => { describe('"wallet_revokeSession" request', () => { it('should pass validation and call next when passed a valid "wallet_revokeSession" request', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 3, jsonrpc: '2.0', method: 'wallet_revokeSession', @@ -385,11 +376,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { describe('"wallet_getSession" request', () => { it('should pass validation and call next when passed a valid "wallet_getSession" request', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 5, jsonrpc: '2.0', method: 'wallet_getSession', - // @ts-expect-error TODO figure out why this type is not working params: {}, }; const response = {} as JsonRpcResponse; @@ -417,11 +407,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); it('should throw an error if the top level params are not an object', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'wallet_invokeMethod', - // @ts-expect-error test params: ['test'], }; const response = {} as JsonRpcResponse; @@ -457,11 +446,10 @@ describe('multichainMethodCallValidatorMiddleware', () => { }); it('should throw an error when passed an unknown method at the top level', async () => { - const request: JsonRpcRequest = { + const request: JsonRpcRequest = { id: 1, jsonrpc: '2.0', method: 'unknown_method', - // @ts-expect-error test params: { request: { method: 'test_method', diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index edd9a0fda2e..3c85c626655 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -2,12 +2,7 @@ import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; import { rpcErrors } from '@metamask/rpc-errors'; import { isObject } from '@metamask/utils'; -import type { - Json, - JsonRpcError, - JsonRpcParams, - JsonRpcRequest, -} from '@metamask/utils'; +import type { Json, JsonRpcError, JsonRpcParams } from '@metamask/utils'; import type { ContentDescriptorObject, MethodObject, @@ -18,12 +13,6 @@ import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-r import type { Schema, ValidationError } from 'jsonschema'; import { Validator } from 'jsonschema'; -import type { - Caip27Params, - Caip285Params, - Caip319Params, -} from '../scope/types'; - const transformError = ( error: ValidationError, param: ContentDescriptorObject, @@ -110,7 +99,7 @@ const multichainMethodCallValidator = async ( }; export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< - JsonRpcRequest | Caip27Params | Caip319Params | Caip285Params, + JsonRpcParams, Json > = function (request, _response, next, end) { // eslint-disable-next-line @typescript-eslint/no-floating-promises diff --git a/packages/multichain/src/scope/types.ts b/packages/multichain/src/scope/types.ts index 4d426be6a15..b13b5edae75 100644 --- a/packages/multichain/src/scope/types.ts +++ b/packages/multichain/src/scope/types.ts @@ -10,7 +10,6 @@ import type { KnownCaipNamespace, CaipNamespace, Json, - JsonRpcParams, } from '@metamask/utils'; /** @@ -120,59 +119,3 @@ export type NonWalletKnownCaipNamespace = Exclude< KnownCaipNamespace, KnownCaipNamespace.Wallet >; - -// { -// "id": 1, -// "jsonrpc": "2.0", -// "method": "wallet_invokeMethod", -// "params": { -// "sessionId": "0xdeadbeef", -// "scope": "eip155:1", -// "request": { -// "method": "eth_sendTransaction", -// "params": [ -// { -// "to": "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7", -// "from": "0xDeaDbeefdEAdbeefdEadbEEFdeadbeefDEADbEEF", -// "gas": "0x76c0", -// "value": "0x8ac7230489e80000", -// "data": "0x", -// "gasPrice": "0x4a817c800" -// } -// ] -// } -// } -// } - -/** - * Parameters for the `wallet_invokeMethod` method as defined in CAIP-27. - */ -export type Caip27Params = { - scope: string; - request: { - method: string; - params: JsonRpcParams; - }; -}; - -/** - * Parameters for the `wallet_notify` method as defined in CAIP-319. - */ -export type Caip319Params = { - scope: string; - notification: { - method: string; - params: JsonRpcParams; - }; -}; - -/** - * Parameters for the `wallet_revokeSession` method as defined in CAIP-285. - */ -export type Caip285Params = { - scope: string; - request: { - method: string; - params: Record; - }; -}; From ca2b3435f6305d3e414c986c5f3a6c78b6e0bdfb Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 5 Dec 2024 14:22:13 -0800 Subject: [PATCH 091/146] Add jsdoc --- .../src/handlers/wallet-revokeSession.ts | 4 ++-- packages/multichain/src/scope/authorization.ts | 10 ++++++++++ packages/multichain/src/scope/constants.ts | 6 ++++++ packages/multichain/src/scope/filter.ts | 17 +++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 51e31073f0d..772e416c726 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -12,14 +12,14 @@ import type { JsonRpcSuccess, Json, JsonRpcRequest } from '@metamask/utils'; import { Caip25EndowmentPermissionName } from '../caip25Permission'; /** - * Handles the `wallet_revokeSession` RPC method. + * Handler for the `wallet_revokeSession` RPC method. * * @param request - The JSON-RPC request object. * @param response - The JSON-RPC response object. * @param _next - The next middleware function. * @param end - The end callback function. * @param hooks - The hooks object. - * @param hooks.revokePermission - The revokePermission function. + * @param hooks.revokePermission - The hook for revoking a permission for an origin function. */ async function walletRevokeSessionHandler( request: JsonRpcRequest & { origin: string }, diff --git a/packages/multichain/src/scope/authorization.ts b/packages/multichain/src/scope/authorization.ts index b3f00cba09e..97d796d8b6d 100644 --- a/packages/multichain/src/scope/authorization.ts +++ b/packages/multichain/src/scope/authorization.ts @@ -53,6 +53,16 @@ export const validateAndNormalizeScopes = ( }; }; +/** + * Groups a NormalizedScopesObject into three separate + * NormalizedScopesObjects for supported scopes, + * supportable scopes, and unsupportable scopes. + * @param scopes - The NormalizedScopesObject to group. + * @param hooks - The hooks. + * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. + * @param hooks.isChainIdSupportable - A helper that returns true if an eth chainId could be supported by the wallet. + * @returns an object with three NormalizedScopesObjects separated by support. + */ export const bucketScopes = ( scopes: NormalizedScopesObject, { diff --git a/packages/multichain/src/scope/constants.ts b/packages/multichain/src/scope/constants.ts index ea1291f7b92..44ba379c359 100644 --- a/packages/multichain/src/scope/constants.ts +++ b/packages/multichain/src/scope/constants.ts @@ -26,8 +26,14 @@ export const KnownWalletRpcMethods: string[] = [ 'wallet_scanQRCode', ]; +/** + * Methods that belong to the `wallet:eip155` scope. + */ const WalletEip155Methods = ['wallet_addEthereumChain']; +/** + * Methods that are only supported via the EIP-1193 API. + */ export const Eip1193OnlyMethods = [ 'wallet_switchEthereumChain', 'wallet_getPermissions', diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index b8ab92f805e..99987b7944b 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -3,6 +3,15 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { assertScopeSupported } from './assert'; import type { NormalizedScopesObject } from './types'; +/** + * Groups a NormalizedScopesObject into two separate + * NormalizedScopesObject with supported scopes in one + * and unsupported scopes in the other. + * @param scopes - The NormalizedScopesObject to group. + * @param hooks - The hooks. + * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. + * @returns an object with two NormalizedScopesObjects separated by support. + */ export const bucketScopesBySupport = ( scopes: NormalizedScopesObject, { @@ -28,6 +37,14 @@ export const bucketScopesBySupport = ( return { supportedScopes, unsupportedScopes }; }; +/** + * Returns a NormalizedScopesObject with only + * scopes that are supported. + * @param scopes - The NormalizedScopesObject to convert. + * @param hooks - The hooks. + * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. + * @returns a NormalizedScopesObject with only scopes that are currently supported. + */ export const filterScopesSupported = ( scopes: NormalizedScopesObject, { From 5f96567fecbda03e67d8eb7cbeec0cfe9238e779 Mon Sep 17 00:00:00 2001 From: jiexi Date: Fri, 6 Dec 2024 12:44:29 -0800 Subject: [PATCH 092/146] Jl/caip multichain api/drop unsupported methods notifications (#5039) ## Explanation Adds and exports `filterScopeObjectsSupported` which filters out unsupported methods and notifications from each ScopeObject in a ScopesObject ## References ### `@metamask/package-a` - ****: Your change here - ****: Your change here ### `@metamask/package-b` - ****: Your change here - ****: Your change here ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- packages/multichain/src/index.test.ts | 1 + packages/multichain/src/index.ts | 1 + packages/multichain/src/scope/filter.test.ts | 191 ++++++++++++++++++- packages/multichain/src/scope/filter.ts | 68 ++++++- 4 files changed, 253 insertions(+), 8 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index d60cd75f138..779069d5b48 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -25,6 +25,7 @@ describe('@metamask/multichain', () => { "KnownWalletNamespaceRpcMethods", "KnownNotifications", "KnownWalletScopeString", + "filterScopeObjectsSupported", "parseScopeString", "normalizeScope", "mergeScopeObject", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index c7fbf580d14..8a4fcddbd96 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -33,6 +33,7 @@ export { KnownNotifications, KnownWalletScopeString, } from './scope/constants'; +export { filterScopeObjectsSupported } from './scope/filter'; export type { ExternalScopeString, ExternalScopeObject, diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts index c49c7397864..a5e2a4239d7 100644 --- a/packages/multichain/src/scope/filter.test.ts +++ b/packages/multichain/src/scope/filter.test.ts @@ -1,11 +1,24 @@ import * as Assert from './assert'; -import { filterScopesSupported, bucketScopesBySupport } from './filter'; +import { + filterScopesSupported, + bucketScopesBySupport, + filterScopeObjectsSupported, +} from './filter'; +import * as Supported from './supported'; jest.mock('./assert', () => ({ + ...jest.requireActual('./assert'), assertScopeSupported: jest.fn(), })); const MockAssert = jest.mocked(Assert); +jest.mock('./supported', () => ({ + ...jest.requireActual('./supported'), + isSupportedMethod: jest.fn(), + isSupportedNotification: jest.fn(), +})); +const MockSupported = jest.mocked(Supported); + describe('filter', () => { afterEach(() => { jest.resetAllMocks(); @@ -165,4 +178,180 @@ describe('filter', () => { }); }); }); + + describe('filterScopeObjectsSupported', () => { + it('checks if each scopeObject method is supported', () => { + filterScopeObjectsSupported({ + 'eip155:1': { + methods: ['method1', 'method2'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['methodA', 'methodB'], + notifications: [], + accounts: [], + }, + }); + + expect(MockSupported.isSupportedMethod).toHaveBeenCalledTimes(4); + expect(MockSupported.isSupportedMethod).toHaveBeenCalledWith( + 'eip155:1', + 'method1', + ); + expect(MockSupported.isSupportedMethod).toHaveBeenCalledWith( + 'eip155:1', + 'method2', + ); + expect(MockSupported.isSupportedMethod).toHaveBeenCalledWith( + 'eip155:5', + 'methodA', + ); + expect(MockSupported.isSupportedMethod).toHaveBeenCalledWith( + 'eip155:5', + 'methodB', + ); + }); + + it('returns only supported methods', () => { + MockSupported.isSupportedMethod.mockImplementation( + (scopeString, method) => { + if (scopeString === 'eip155:1' && method === 'method1') { + return false; + } + if (scopeString === 'eip155:5' && method === 'methodB') { + return false; + } + return true; + }, + ); + + const result = filterScopeObjectsSupported({ + 'eip155:1': { + methods: ['method1', 'method2'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['methodA', 'methodB'], + notifications: [], + accounts: [], + }, + }); + + expect(result).toStrictEqual({ + 'eip155:1': { + methods: ['method2'], + notifications: [], + accounts: [], + }, + 'eip155:5': { + methods: ['methodA'], + notifications: [], + accounts: [], + }, + }); + }); + + it('checks if each scopeObject notification is supported', () => { + filterScopeObjectsSupported({ + 'eip155:1': { + methods: [], + notifications: ['notification1', 'notification2'], + accounts: [], + }, + 'eip155:5': { + methods: [], + notifications: ['notificationA', 'notificationB'], + accounts: [], + }, + }); + + expect(MockSupported.isSupportedNotification).toHaveBeenCalledTimes(4); + expect(MockSupported.isSupportedNotification).toHaveBeenCalledWith( + 'eip155:1', + 'notification1', + ); + expect(MockSupported.isSupportedNotification).toHaveBeenCalledWith( + 'eip155:1', + 'notification2', + ); + expect(MockSupported.isSupportedNotification).toHaveBeenCalledWith( + 'eip155:5', + 'notificationA', + ); + expect(MockSupported.isSupportedNotification).toHaveBeenCalledWith( + 'eip155:5', + 'notificationB', + ); + }); + + it('returns only supported notifications', () => { + MockSupported.isSupportedNotification.mockImplementation( + (scopeString, notification) => { + if (scopeString === 'eip155:1' && notification === 'notification1') { + return false; + } + if (scopeString === 'eip155:5' && notification === 'notificationB') { + return false; + } + return true; + }, + ); + + const result = filterScopeObjectsSupported({ + 'eip155:1': { + methods: [], + notifications: ['notification1', 'notification2'], + accounts: [], + }, + 'eip155:5': { + methods: [], + notifications: ['notificationA', 'notificationB'], + accounts: [], + }, + }); + + expect(result).toStrictEqual({ + 'eip155:1': { + methods: [], + notifications: ['notification2'], + accounts: [], + }, + 'eip155:5': { + methods: [], + notifications: ['notificationA'], + accounts: [], + }, + }); + }); + + it('does not modify accounts', () => { + const result = filterScopeObjectsSupported({ + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0xdeadbeef'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xdeadbeef'], + }, + }); + + expect(result).toStrictEqual({ + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0xdeadbeef'], + }, + 'eip155:5': { + methods: [], + notifications: [], + accounts: ['eip155:5:0xdeadbeef'], + }, + }); + }); + }); }); diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index 99987b7944b..bf42a9887a8 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -1,7 +1,12 @@ -import type { CaipChainId, Hex } from '@metamask/utils'; +import { type Hex } from '@metamask/utils'; -import { assertScopeSupported } from './assert'; -import type { NormalizedScopesObject } from './types'; +import { assertIsInternalScopeString, assertScopeSupported } from './assert'; +import { isSupportedMethod, isSupportedNotification } from './supported'; +import type { + InternalScopeString, + NormalizedScopeObject, + NormalizedScopesObject, +} from './types'; /** * Groups a NormalizedScopesObject into two separate @@ -24,13 +29,14 @@ export const bucketScopesBySupport = ( const unsupportedScopes: NormalizedScopesObject = {}; for (const [scopeString, scopeObject] of Object.entries(scopes)) { + assertIsInternalScopeString(scopeString); try { assertScopeSupported(scopeString, scopeObject, { isChainIdSupported, }); - supportedScopes[scopeString as CaipChainId] = scopeObject; + supportedScopes[scopeString] = scopeObject; } catch (err) { - unsupportedScopes[scopeString as CaipChainId] = scopeObject; + unsupportedScopes[scopeString] = scopeObject; } } @@ -39,8 +45,8 @@ export const bucketScopesBySupport = ( /** * Returns a NormalizedScopesObject with only - * scopes that are supported. - * @param scopes - The NormalizedScopesObject to convert. + * scopes that are supported entirely as is. + * @param scopes - The NormalizedScopesObject to filter. * @param hooks - The hooks. * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. * @returns a NormalizedScopesObject with only scopes that are currently supported. @@ -59,3 +65,51 @@ export const filterScopesSupported = ( return supportedScopes; }; + +/** + * Returns a NormalizedScopeObject with + * unsupported methods and notifications removed. + * @param scopeString - The InternalScopeString for the scopeObject. + * @param scopeObject - The NormalizedScopeObject to filter. + * @returns a NormalizedScopeObject with only methods and notifications that are currently supported. + */ +const filterScopeObjectSupported = ( + scopeString: InternalScopeString, + scopeObject: NormalizedScopeObject, +) => { + const { methods, notifications } = scopeObject; + + const supportedMethods = methods.filter((method) => + isSupportedMethod(scopeString, method), + ); + + const supportedNotifications = notifications.filter((notification) => + isSupportedNotification(scopeString, notification), + ); + + return { + ...scopeObject, + methods: supportedMethods, + notifications: supportedNotifications, + }; +}; + +/** + * Returns a NormalizedScopesObject with + * unsupported methods and notifications removed from scopeObjects. + * @param scopes - The NormalizedScopesObject to filter. + * @returns a NormalizedScopesObject with only methods, and notifications that are currently supported. + */ +export const filterScopeObjectsSupported = (scopes: NormalizedScopesObject) => { + const filteredScopesObject: NormalizedScopesObject = {}; + + for (const [scopeString, scopeObject] of Object.entries(scopes)) { + assertIsInternalScopeString(scopeString); + filteredScopesObject[scopeString] = filterScopeObjectSupported( + scopeString, + scopeObject, + ); + } + + return filteredScopesObject; +}; From b6765a494dfabbae4ac21f5d7901842462f9365c Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:55:46 -0800 Subject: [PATCH 093/146] Update packages/multichain/src/adapters/caip-permission-adapter-middleware.ts Co-authored-by: Elliot Winkler --- .../src/adapters/caip-permission-adapter-middleware.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 89b47e8f81b..c8c7e081c75 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -64,12 +64,12 @@ export async function caipPermissionAdapterMiddleware( const scope: InternalScopeString = `eip155:${parseInt(chainId, 16)}`; - const sesionScopes = getSessionScopes(caveat.value); + const sessionScopes = getSessionScopes(caveat.value); if ( - !sesionScopes[scope]?.methods?.includes(method) && - !sesionScopes[KnownWalletScopeString.Eip155]?.methods?.includes(method) && - !sesionScopes.wallet?.methods?.includes(method) && + !sessionScopes[scope]?.methods?.includes(method) && + !sessionScopes[KnownWalletScopeString.Eip155]?.methods?.includes(method) && + !sessionScopes.wallet?.methods?.includes(method) && !Eip1193OnlyMethods.includes(method) ) { return end(providerErrors.unauthorized()); From e6a3346da647c64d8f65d5392e01ca199d6c85ec Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:56:04 -0800 Subject: [PATCH 094/146] Update packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts Co-authored-by: Elliot Winkler --- .../src/middlewares/multichainMethodCallValidator.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index cc10661aa27..72fee461196 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -8,9 +8,6 @@ import { multichainMethodCallValidatorMiddleware } from './multichainMethodCallV describe('multichainMethodCallValidatorMiddleware', () => { const mockNext = jest.fn(); - beforeEach(() => { - jest.clearAllMocks(); - }); describe('"wallet_invokeMethod" request', () => { it('should pass validation and call next when passed a valid "wallet_invokeMethod" request', async () => { From c0637f04de07b93093c1e7f9c9eef8d4927f6087 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:56:12 -0800 Subject: [PATCH 095/146] Update packages/multichain/src/handlers/wallet-getSession.test.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-getSession.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index 25833942035..965f5ec30f6 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -67,10 +67,6 @@ const createMockedHandler = () => { }; describe('wallet_getSession', () => { - afterEach(() => { - jest.restoreAllMocks(); - }); - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { const { handler, getCaveat } = createMockedHandler(); From d8d90ce44f9cdbbf31a1dbaa4445e6dbb98c49c2 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:56:17 -0800 Subject: [PATCH 096/146] Update packages/multichain/src/handlers/wallet-invokeMethod.test.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-invokeMethod.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index a608e2866f7..a8baff8a3c4 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -108,10 +108,6 @@ describe('wallet_invokeMethod', () => { }); }); - afterEach(() => { - jest.restoreAllMocks(); - }); - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { const request = createMockedRequest(); const { handler, getCaveat } = createMockedHandler(); From c102e379321c0ce45d5481c01487479b77f27120 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:59:08 -0800 Subject: [PATCH 097/146] Update packages/multichain/src/scope/filter.test.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/scope/filter.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts index a5e2a4239d7..2b50fef4405 100644 --- a/packages/multichain/src/scope/filter.test.ts +++ b/packages/multichain/src/scope/filter.test.ts @@ -20,10 +20,6 @@ jest.mock('./supported', () => ({ const MockSupported = jest.mocked(Supported); describe('filter', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - describe('filterScopesSupported', () => { const isChainIdSupported = jest.fn(); From 3d68f83e6b6a0abee98968104b52132cf7e0b578 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:59:21 -0800 Subject: [PATCH 098/146] Update packages/multichain/src/adapters/caip-permission-adapter-middleware.ts Co-authored-by: Elliot Winkler --- .../src/adapters/caip-permission-adapter-middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index c8c7e081c75..158bda6edba 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -19,7 +19,7 @@ import { getSessionScopes } from './caip-permission-adapter-session-scopes'; * Middleware to handle CAIP-25 permission requests. * * @param request - The request object. - * @param _response - The response object. + * @param _response - The response object. Unused. * @param next - The next middleware function. * @param end - The end function. * @param hooks - The hooks object. From d997b821636fadbdba8699889ac15bb1b813b866 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:59:32 -0800 Subject: [PATCH 099/146] Update packages/multichain/src/handlers/wallet-getSession.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-getSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 6a8f4bf2fb6..03ca487474a 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -14,7 +14,7 @@ import { * * @param request - The request object. * @param response - The response object. - * @param _next - The next middleware function. + * @param _next - The next middleware function. Unused. * @param end - The end function. * @param hooks - The hooks object. * @param hooks.getCaveat - Function to retrieve a caveat. From a3e9d8f349408a0d7ff1570b31aad343f3299bd0 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 11:59:42 -0800 Subject: [PATCH 100/146] Update packages/multichain/src/handlers/wallet-invokeMethod.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-invokeMethod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 4e9f6002bd5..c69c83fab9f 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -21,7 +21,7 @@ import { parseScopeString } from '../scope/types'; * Handler for the `wallet_invokeMethod` RPC method. * * @param request - The request object. - * @param _response - The response object. + * @param _response - The response object. Unused. * @param next - The next middleware function. * @param end - The end function. * @param hooks - The hooks object. From 7f11b8a78aa8927efc8bb53cc33118b2d9bec847 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 12:00:57 -0800 Subject: [PATCH 101/146] Update packages/multichain/src/handlers/wallet-revokeSession.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-revokeSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 772e416c726..3f6e5c23e8c 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -16,7 +16,7 @@ import { Caip25EndowmentPermissionName } from '../caip25Permission'; * * @param request - The JSON-RPC request object. * @param response - The JSON-RPC response object. - * @param _next - The next middleware function. + * @param _next - The next middleware function. Unused. * @param end - The end callback function. * @param hooks - The hooks object. * @param hooks.revokePermission - The hook for revoking a permission for an origin function. From f94c4f6a92d7898d1105a6bf89ea1be25fa68082 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:14:23 -0800 Subject: [PATCH 102/146] Improve wallet_getSession, invokeSession, revokeSession jsdoc --- packages/multichain/src/handlers/wallet-getSession.ts | 5 ++++- packages/multichain/src/handlers/wallet-invokeMethod.ts | 4 +++- packages/multichain/src/handlers/wallet-revokeSession.ts | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index 03ca487474a..cf2d6d2136e 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -10,7 +10,10 @@ import { } from '../caip25Permission'; /** - * Handler for the `wallet_getSession` RPC method. + * Handler for the `wallet_getSession` RPC method as specified by [CAIP-312](https://chainagnostic.org/CAIPs/caip-312). + * The implementation below deviates from the linked spec in that it ignores the `sessionId` param entirely, + * and that an empty object is returned for the `sessionScopes` result rather than throwing an error if there + * is no active session for the origin. * * @param request - The request object. * @param response - The response object. diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index c69c83fab9f..185ea01bb6e 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -18,7 +18,9 @@ import type { ExternalScopeString } from '../scope/types'; import { parseScopeString } from '../scope/types'; /** - * Handler for the `wallet_invokeMethod` RPC method. + * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27). + * The implementation below deviates from the linked spec in that it ignores the `sessionId` param + * and instead uses the singular session for the origin if available. * * @param request - The request object. * @param _response - The response object. Unused. diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 3f6e5c23e8c..6bc628cf30f 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -12,7 +12,11 @@ import type { JsonRpcSuccess, Json, JsonRpcRequest } from '@metamask/utils'; import { Caip25EndowmentPermissionName } from '../caip25Permission'; /** - * Handler for the `wallet_revokeSession` RPC method. + * Handler for the `wallet_revokeSession` RPC method as specified by [CAIP-285](https://chainagnostic.org/CAIPs/caip-285). + * The implementation below deviates from the linked spec in that it ignores the `sessionId` param + * and instead revokes the singular session for the origin if available. Additionally, + * the handler also does not return an error if there is currently no active session and instead + * returns true which is the same result returned if an active session was actually revoked. * * @param request - The JSON-RPC request object. * @param response - The JSON-RPC response object. From d1aad26b17e63ef9e2a6772b8b9265356dc0e4ae Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 13:17:09 -0800 Subject: [PATCH 103/146] Update packages/multichain/src/handlers/wallet-invokeMethod.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-invokeMethod.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 185ea01bb6e..0c845e846f8 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -32,7 +32,13 @@ import { parseScopeString } from '../scope/types'; * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. */ async function walletInvokeMethodHandler( - request: JsonRpcRequest & { origin: string }, + request: JsonRpcRequest & { + origin: string; + params: { + scope: ExternalScopeString; + request: Pick; + }; + }, _response: PendingJsonRpcResponse, next: () => void, end: (error: Error) => void, From da3fb044d305458cb99f902146d12d8056219208 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:19:22 -0800 Subject: [PATCH 104/146] Fix walletInvokeMethodHandler type --- packages/multichain/src/handlers/wallet-invokeMethod.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 0c845e846f8..447255b80bd 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -36,7 +36,7 @@ async function walletInvokeMethodHandler( origin: string; params: { scope: ExternalScopeString; - request: Pick; + request: Pick; }; }, _response: PendingJsonRpcResponse, @@ -52,10 +52,7 @@ async function walletInvokeMethodHandler( getSelectedNetworkClientId: () => string; }, ) { - const { scope, request: wrappedRequest } = request.params as { - scope: ExternalScopeString; - request: JsonRpcRequest; - }; + const { scope, request: wrappedRequest } = request.params; assertIsInternalScopeString(scope); From 4a7ae5d7db6bd9c487e228e4a4b12ec4be1d8331 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 13:20:34 -0800 Subject: [PATCH 105/146] Update packages/multichain/src/handlers/wallet-invokeMethod.ts Co-authored-by: Elliot Winkler --- packages/multichain/src/handlers/wallet-invokeMethod.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 447255b80bd..28766df5c68 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -48,8 +48,8 @@ async function walletInvokeMethodHandler( endowmentPermissionName: string, caveatType: string, ) => Caveat; - findNetworkClientIdByChainId: (chainId: string) => string | undefined; - getSelectedNetworkClientId: () => string; + findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined; + getSelectedNetworkClientId: () => NetworkClientId; }, ) { const { scope, request: wrappedRequest } = request.params; From c54714f57da09b859fcf2422651eb4a732e5da63 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 13:25:25 -0800 Subject: [PATCH 106/146] Update packages/multichain/src/middlewares/MultichainMiddlewareManager.ts Co-authored-by: Elliot Winkler --- .../src/middlewares/MultichainMiddlewareManager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 32109a8c569..81c9e3f0a47 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -66,8 +66,9 @@ export class MultichainMiddlewareManager { #removeMiddleware(middlewareEntry: MiddlewareEntry) { // When the destroy function on the middleware is async, // we don't need to wait for it complete - // eslint-disable-next-line no-void - void middlewareEntry.middleware.destroy?.(); + Promise.resolve(middlewareEntry.middleware.destroy?.()).catch(() => { + // do nothing + }); this.#removeMiddlewareEntry(middlewareEntry); } From 840d27da4ab9d3e72f437d3a5f03e81e51a7fbf3 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:34:33 -0800 Subject: [PATCH 107/146] add MultichainMiddlewareManager desc --- packages/multichain/src/handlers/wallet-invokeMethod.ts | 2 ++ .../src/middlewares/MultichainMiddlewareManager.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 28766df5c68..baf215c1a5e 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -1,6 +1,8 @@ +import type { NetworkClientId } from '@metamask/network-controller'; import type { Caveat } from '@metamask/permission-controller'; import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; import type { + Hex, Json, JsonRpcRequest, PendingJsonRpcResponse, diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 32109a8c569..0e5bbfa1c4a 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -29,6 +29,11 @@ type MiddlewareEntry = MiddlewareKey & { middleware: ExtendedJsonRpcMiddleware; }; +/** + * A helper that facilates registering and calling of provided middleware instances + * in the RPC pipeline based on the incoming request's scope, origin, and tabId. + * Note that only one middleware instance can be registered per scope, origin, tabId key. + */ export class MultichainMiddlewareManager { #middlewares: MiddlewareEntry[] = []; From 8874ebcbc5620fac8f743a2ff351b35483fa411a Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:39:25 -0800 Subject: [PATCH 108/146] add MultichainSubscriptionManager desc --- .../src/middlewares/MultichainSubscriptionManager.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 22e92705247..4e6c0529e06 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -37,6 +37,10 @@ type MultichainSubscriptionManagerOptions = { getNetworkClientById: NetworkController['getNetworkClientById']; }; +/** + * A helper that facilates the lifecycle of a SubscriptionManager instance that + * is meant to handle subscriptons for only one specific scope, origin, and tabId combination. + */ export class MultichainSubscriptionManager extends SafeEventEmitter { #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; @@ -44,6 +48,13 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { #subscriptions: SubscriptionEntry[] = []; + /** + * Construct a MultichainSubscriptionManager. + * + * @param options - The controller options. + * @param options.findNetworkClientIdByChainId - The hook to get the networkClientId from a chainId. + * @param options.getNetworkClientById - The hook to get the network client instance by its networkClientId. + */ constructor(options: MultichainSubscriptionManagerOptions) { super(); this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId; From ff57ba39b51692f2b39e94aac021cedba77a3720 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:46:51 -0800 Subject: [PATCH 109/146] rename onNotification to notify --- .../src/middlewares/MultichainSubscriptionManager.test.ts | 6 +++--- .../src/middlewares/MultichainSubscriptionManager.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts index 010effb025f..75c6d3df05f 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.test.ts @@ -94,14 +94,14 @@ describe('MultichainSubscriptionManager', () => { const { multichainSubscriptionManager } = createMultichainSubscriptionManager(); multichainSubscriptionManager.subscribe({ scope, origin, tabId }); - const onNotificationSpy = jest.fn(); - multichainSubscriptionManager.on('notification', onNotificationSpy); + const notifySpy = jest.fn(); + multichainSubscriptionManager.on('notification', notifySpy); mockSubscriptionManager.events.on.mock.calls[0][1]( newHeadsNotificationMock, ); - expect(onNotificationSpy).toHaveBeenCalledWith(origin, tabId, { + expect(notifySpy).toHaveBeenCalledWith(origin, tabId, { method: 'wallet_notify', params: { scope, diff --git a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts index 4e6c0529e06..9df0bb48518 100644 --- a/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts +++ b/packages/multichain/src/middlewares/MultichainSubscriptionManager.ts @@ -61,7 +61,7 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { this.#getNetworkClientById = options.getNetworkClientById; } - onNotification( + notify( { scope, origin, tabId }: SubscriptionKey, { method, params }: SubscriptionNotificationEvent, ) { @@ -116,7 +116,7 @@ export class MultichainSubscriptionManager extends SafeEventEmitter { subscriptionManager.events.on( 'notification', (message: SubscriptionNotificationEvent) => { - this.onNotification(subscriptionKey, message); + this.notify(subscriptionKey, message); }, ); From dc0283ef7acf14b58c39fb3ec1a1c584d96012bb Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 13:54:03 -0800 Subject: [PATCH 110/146] rename filter helpers --- packages/multichain/src/index.test.ts | 2 +- packages/multichain/src/index.ts | 2 +- packages/multichain/src/scope/filter.test.ts | 22 ++++++++++---------- packages/multichain/src/scope/filter.ts | 8 +++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index 81eee37d27d..aa2515458c6 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -25,7 +25,7 @@ describe('@metamask/multichain', () => { "KnownWalletNamespaceRpcMethods", "KnownNotifications", "KnownWalletScopeString", - "filterScopeObjectsSupported", + "getSupportedScopeObjects", "parseScopeString", "normalizeScope", "mergeScopeObject", diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 1d097d6131f..49b53a38e0d 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -33,7 +33,7 @@ export { KnownNotifications, KnownWalletScopeString, } from './scope/constants'; -export { filterScopeObjectsSupported } from './scope/filter'; +export { getSupportedScopeObjects } from './scope/filter'; export type { ExternalScopeString, ExternalScopeObject, diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts index 2b50fef4405..09877ef59da 100644 --- a/packages/multichain/src/scope/filter.test.ts +++ b/packages/multichain/src/scope/filter.test.ts @@ -1,8 +1,8 @@ import * as Assert from './assert'; import { - filterScopesSupported, + getSupportedScopes, bucketScopesBySupport, - filterScopeObjectsSupported, + getSupportedScopeObjects, } from './filter'; import * as Supported from './supported'; @@ -20,11 +20,11 @@ jest.mock('./supported', () => ({ const MockSupported = jest.mocked(Supported); describe('filter', () => { - describe('filterScopesSupported', () => { + describe('getSupportedScopes', () => { const isChainIdSupported = jest.fn(); it('checks if each scope is supported', () => { - filterScopesSupported( + getSupportedScopes( { 'eip155:1': { methods: ['a'], @@ -68,7 +68,7 @@ describe('filter', () => { }); expect( - filterScopesSupported( + getSupportedScopes( { 'eip155:1': { methods: ['a'], @@ -175,9 +175,9 @@ describe('filter', () => { }); }); - describe('filterScopeObjectsSupported', () => { + describe('getSupportedScopeObjects', () => { it('checks if each scopeObject method is supported', () => { - filterScopeObjectsSupported({ + getSupportedScopeObjects({ 'eip155:1': { methods: ['method1', 'method2'], notifications: [], @@ -222,7 +222,7 @@ describe('filter', () => { }, ); - const result = filterScopeObjectsSupported({ + const result = getSupportedScopeObjects({ 'eip155:1': { methods: ['method1', 'method2'], notifications: [], @@ -250,7 +250,7 @@ describe('filter', () => { }); it('checks if each scopeObject notification is supported', () => { - filterScopeObjectsSupported({ + getSupportedScopeObjects({ 'eip155:1': { methods: [], notifications: ['notification1', 'notification2'], @@ -295,7 +295,7 @@ describe('filter', () => { }, ); - const result = filterScopeObjectsSupported({ + const result = getSupportedScopeObjects({ 'eip155:1': { methods: [], notifications: ['notification1', 'notification2'], @@ -323,7 +323,7 @@ describe('filter', () => { }); it('does not modify accounts', () => { - const result = filterScopeObjectsSupported({ + const result = getSupportedScopeObjects({ 'eip155:1': { methods: [], notifications: [], diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index bf42a9887a8..8c4758632d3 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -51,7 +51,7 @@ export const bucketScopesBySupport = ( * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. * @returns a NormalizedScopesObject with only scopes that are currently supported. */ -export const filterScopesSupported = ( +export const getSupportedScopes = ( scopes: NormalizedScopesObject, { isChainIdSupported, @@ -73,7 +73,7 @@ export const filterScopesSupported = ( * @param scopeObject - The NormalizedScopeObject to filter. * @returns a NormalizedScopeObject with only methods and notifications that are currently supported. */ -const filterScopeObjectSupported = ( +const getSupportedScopeObject = ( scopeString: InternalScopeString, scopeObject: NormalizedScopeObject, ) => { @@ -100,12 +100,12 @@ const filterScopeObjectSupported = ( * @param scopes - The NormalizedScopesObject to filter. * @returns a NormalizedScopesObject with only methods, and notifications that are currently supported. */ -export const filterScopeObjectsSupported = (scopes: NormalizedScopesObject) => { +export const getSupportedScopeObjects = (scopes: NormalizedScopesObject) => { const filteredScopesObject: NormalizedScopesObject = {}; for (const [scopeString, scopeObject] of Object.entries(scopes)) { assertIsInternalScopeString(scopeString); - filteredScopesObject[scopeString] = filterScopeObjectSupported( + filteredScopesObject[scopeString] = getSupportedScopeObject( scopeString, scopeObject, ); From b4394618e0aca704d45f8a9009a4ecd2c5de6db9 Mon Sep 17 00:00:00 2001 From: jiexi Date: Tue, 17 Dec 2024 13:56:43 -0800 Subject: [PATCH 111/146] Update packages/multichain/src/middlewares/multichainMethodCallValidator.ts Co-authored-by: Elliot Winkler --- .../multichainMethodCallValidator.ts | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index 3c85c626655..e870f27b249 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -98,17 +98,15 @@ const multichainMethodCallValidator = async ( return false; }; -export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< - JsonRpcParams, - Json -> = function (request, _response, next, end) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - multichainMethodCallValidator(request.method, request.params).then( - (errors) => { - if (errors) { - return end(rpcErrors.invalidParams({ data: errors })); - } - return next(); - }, - ); -}; +export const multichainMethodCallValidatorMiddleware = createAsyncMiddleware( + async (request, _response, next) => { + const errors = await multichainMethodCallValidator( + request.method, + request.params, + ); + if (errors) { + throw rpcErrors.invalidParams({ data: errors }); + } + return await next(); + }, +); From e77e87f08d18a2ab618bba2133a4ba00f3b81190 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 14:23:26 -0800 Subject: [PATCH 112/146] cleanup multichainMethodCallValidator --- .../multichainMethodCallValidator.ts | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index 3c85c626655..77c23bc1b75 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -1,12 +1,13 @@ import { MultiChainOpenRPCDocument } from '@metamask/api-specs'; -import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine'; +import { createAsyncMiddleware } from '@metamask/json-rpc-engine'; import { rpcErrors } from '@metamask/rpc-errors'; import { isObject } from '@metamask/utils'; -import type { Json, JsonRpcError, JsonRpcParams } from '@metamask/utils'; +import type { JsonRpcError, JsonRpcParams } from '@metamask/utils'; import type { ContentDescriptorObject, MethodObject, OpenrpcDocument, + ReferenceObject, } from '@open-rpc/meta-schema'; import dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document'; import { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document'; @@ -41,6 +42,15 @@ const dereffedPromise = dereferenceDocument( MultiChainOpenRPCDocument as unknown as OpenrpcDocument, makeCustomResolver({}), ); + +/** + * Helper that utilizes the Multichain method specifications from `@metamask/api-specs` + * to validate the params of a Multichain request. + * + * @param method - The request's method. + * @param params - The request's optional JsonRpcParams object. + * @returns an array of error objects for each validation error or an empty array if no errors. + */ const multichainMethodCallValidator = async ( method: string, params: JsonRpcParams | undefined, @@ -48,10 +58,9 @@ const multichainMethodCallValidator = async ( const dereffed = await dereffedPromise; const methodToCheck = dereffed.methods.find( - (m) => (m as unknown as ContentDescriptorObject).name === method, - ); + (m: MethodObject | ReferenceObject) => (m as MethodObject).name === method, + ) as MethodObject | undefined; - const errors: JsonRpcError[] = []; if ( !methodToCheck || !isObject(methodToCheck) || @@ -67,16 +76,18 @@ const multichainMethodCallValidator = async ( }, ]; } - // check each param and aggregate errors - (methodToCheck as unknown as MethodObject).params.forEach((param) => { - const p = param as ContentDescriptorObject; + + const errors: JsonRpcError[] = []; + for (const param of methodToCheck.params) { if (!isObject(params)) { - errors.push({ - code: -32602, - message: 'Invalid method parameter(s).', - }); - return; + return [ + { + code: -32602, + message: 'Invalid method parameter(s).', + }, + ]; } + const p = param as ContentDescriptorObject; const paramToCheck = params[p.name]; const result = v.validate(paramToCheck, p.schema as unknown as Schema, { @@ -89,26 +100,23 @@ const multichainMethodCallValidator = async ( }), ); } - }); - if (errors.length > 0) { - return errors; } - // feels like this should return true to indicate that its valid but i'd rather check the falsy value since errors - // would be an array and return true if it's empty - return false; + return errors; }; -export const multichainMethodCallValidatorMiddleware: JsonRpcMiddleware< - JsonRpcParams, - Json -> = function (request, _response, next, end) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - multichainMethodCallValidator(request.method, request.params).then( - (errors) => { - if (errors) { - return end(rpcErrors.invalidParams({ data: errors })); - } - return next(); - }, - ); -}; +/** + * Middleware that validates the params of a Multichain method request + * using the specifications from `@metamask/api-specs`. + */ +export const multichainMethodCallValidatorMiddleware = createAsyncMiddleware( + async (request, _response, next) => { + const errors = await multichainMethodCallValidator( + request.method, + request.params, + ); + if (errors.length > 0) { + throw rpcErrors.invalidParams({ data: errors }); + } + return await next(); + }, +); From 3f65e2221bff1ba1a69d99dddc963318188411b8 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 14:30:05 -0800 Subject: [PATCH 113/146] Add walletInvokeMethodRequest type --- .../src/handlers/wallet-invokeMethod.test.ts | 4 ++-- .../src/handlers/wallet-invokeMethod.ts | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index a8baff8a3c4..18cab6df74b 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -6,7 +6,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { walletInvokeMethod } from './wallet-invokeMethod'; +import { walletInvokeMethod, WalletInvokeMethodRequest } from './wallet-invokeMethod'; jest.mock('../adapters/caip-permission-adapter-session-scopes', () => ({ getSessionScopes: jest.fn(), @@ -59,7 +59,7 @@ const createMockedHandler = () => { const getSelectedNetworkClientId = jest .fn() .mockReturnValue('selectedNetworkClientId'); - const handler = (request: JsonRpcRequest & { origin: string }) => + const handler = (request: WalletInvokeMethodRequest) => walletInvokeMethod.implementation( request, { jsonrpc: '2.0', id: 1 }, diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index baf215c1a5e..0360ba50c6e 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -19,6 +19,14 @@ import { assertIsInternalScopeString } from '../scope/assert'; import type { ExternalScopeString } from '../scope/types'; import { parseScopeString } from '../scope/types'; +export type WalletInvokeMethodRequest = JsonRpcRequest & { + origin: string; + params: { + scope: ExternalScopeString; + request: Pick; + }; +} + /** * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27). * The implementation below deviates from the linked spec in that it ignores the `sessionId` param @@ -34,13 +42,7 @@ import { parseScopeString } from '../scope/types'; * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. */ async function walletInvokeMethodHandler( - request: JsonRpcRequest & { - origin: string; - params: { - scope: ExternalScopeString; - request: Pick; - }; - }, + request: WalletInvokeMethodRequest, _response: PendingJsonRpcResponse, next: () => void, end: (error: Error) => void, From 1399f971bec384bf9bb1c13a31d76af6e47b3003 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 14:41:00 -0800 Subject: [PATCH 114/146] Add MultichainMiddlewareManager.test.ts to get back to 100% --- .../src/handlers/wallet-invokeMethod.test.ts | 4 +- .../src/handlers/wallet-invokeMethod.ts | 2 +- .../MultichainMiddlewareManager.test.ts | 80 ++++++++++++++++++- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index 18cab6df74b..bbaa990a073 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -1,12 +1,12 @@ import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; import * as PermissionAdapterSessionScopes from '../adapters/caip-permission-adapter-session-scopes'; import { Caip25CaveatType, Caip25EndowmentPermissionName, } from '../caip25Permission'; -import { walletInvokeMethod, WalletInvokeMethodRequest } from './wallet-invokeMethod'; +import type { WalletInvokeMethodRequest } from './wallet-invokeMethod'; +import { walletInvokeMethod } from './wallet-invokeMethod'; jest.mock('../adapters/caip-permission-adapter-session-scopes', () => ({ getSessionScopes: jest.fn(), diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 0360ba50c6e..7c9a9ae496e 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -25,7 +25,7 @@ export type WalletInvokeMethodRequest = JsonRpcRequest & { scope: ExternalScopeString; request: Pick; }; -} +}; /** * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27). diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 4a358896fce..85374e9ab25 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -41,7 +41,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed', async () => { + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware has no destroy function', async () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; multichainMiddlewareManager.addMiddleware({ @@ -73,6 +73,84 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware destroy function resolves', async () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + jest + .spyOn(middlewareSpy, 'destroy') + .mockImplementation() + .mockResolvedValue({}); + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + await middleware.destroy?.(); + + expect(middlewareSpy.destroy).toHaveBeenCalled(); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware destroy function rejects', async () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + jest + .spyOn(middlewareSpy, 'destroy') + .mockImplementation() + .mockRejectedValue( + new Error('failed to destroy the actual underlying middleware'), + ); + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + await middleware.destroy?.(); + + expect(middlewareSpy.destroy).toHaveBeenCalled(); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + it('should remove middleware by scope', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; From 0fd56ce32dfbfe2494065631d524efc3db7f591c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 14:47:03 -0800 Subject: [PATCH 115/146] fix type --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 85374e9ab25..a665b5e150a 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -79,7 +79,7 @@ describe('MultichainMiddlewareManager', () => { jest .spyOn(middlewareSpy, 'destroy') .mockImplementation() - .mockResolvedValue({}); + .mockResolvedValue(); multichainMiddlewareManager.addMiddleware({ scope, origin, From bf4e136fba47ba885bc7663bbe89a648baa4a396 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 17 Dec 2024 14:55:56 -0800 Subject: [PATCH 116/146] fix types. Ignore linter prefer-spy-on --- .../middlewares/MultichainMiddlewareManager.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index a665b5e150a..ac65138b2ec 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -76,10 +76,8 @@ describe('MultichainMiddlewareManager', () => { it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware destroy function resolves', async () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - jest - .spyOn(middlewareSpy, 'destroy') - .mockImplementation() - .mockResolvedValue(); + // eslint-disable-next-line jest/prefer-spy-on + middlewareSpy.destroy = jest.fn().mockResolvedValue(undefined); multichainMiddlewareManager.addMiddleware({ scope, origin, @@ -114,9 +112,9 @@ describe('MultichainMiddlewareManager', () => { it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware destroy function rejects', async () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; - jest - .spyOn(middlewareSpy, 'destroy') - .mockImplementation() + // eslint-disable-next-line jest/prefer-spy-on + middlewareSpy.destroy = jest + .fn() .mockRejectedValue( new Error('failed to destroy the actual underlying middleware'), ); From 7c4aa65b105fcdb4b1f3810c52470cc2b14d2180 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 6 Jan 2025 11:42:31 -0800 Subject: [PATCH 117/146] align package versions --- packages/multichain/package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/multichain/package.json b/packages/multichain/package.json index 9a2ddc16c21..72482d32620 100644 --- a/packages/multichain/package.json +++ b/packages/multichain/package.json @@ -59,7 +59,7 @@ }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", - "@metamask/json-rpc-engine": "^10.0.1", + "@metamask/json-rpc-engine": "^10.0.2", "@metamask/network-controller": "^22.1.1", "@metamask/permission-controller": "^11.0.4", "@open-rpc/meta-schema": "^1.14.6", diff --git a/yarn.lock b/yarn.lock index 99b3832fedc..378c0450d7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3315,7 +3315,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/controller-utils": "npm:^11.4.4" "@metamask/eth-json-rpc-filters": "npm:^9.0.0" - "@metamask/json-rpc-engine": "npm:^10.0.1" + "@metamask/json-rpc-engine": "npm:^10.0.2" "@metamask/network-controller": "npm:^22.1.1" "@metamask/permission-controller": "npm:^11.0.4" "@metamask/rpc-errors": "npm:^7.0.2" From 4ad37a9be40778a6c60535672f061d8f4ac30707 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 8 Jan 2025 08:42:40 -0800 Subject: [PATCH 118/146] fix cross-spawn --- package.json | 3 +++ yarn.lock | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 4beb3ae7879..c27f339e9ee 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,9 @@ "pre-push": "yarn lint" }, "resolutions": { + "cross-spawn@^7.0.0": "^7.0.5", + "cross-spawn@^7.0.2": "^7.0.5", + "cross-spawn@^7.0.3": "^7.0.5", "elliptic@6.5.4": "^6.5.7", "fast-xml-parser@^4.3.4": "^4.4.1", "ws@7.4.6": "^7.5.10" diff --git a/yarn.lock b/yarn.lock index 378c0450d7a..15ae53737e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7180,14 +7180,14 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" +"cross-spawn@npm:^7.0.5": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" dependencies: path-key: "npm:^3.1.0" shebang-command: "npm:^2.0.0" which: "npm:^2.0.1" - checksum: 10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce + checksum: 10/0d52657d7ae36eb130999dffff1168ec348687b48dd38e2ff59992ed916c88d328cf1d07ff4a4a10bc78de5e1c23f04b306d569e42f7a2293915c081e4dfee86 languageName: node linkType: hard From 43d1dcd5a5a37827e588a43f2a572ee38010e09d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 8 Jan 2025 08:45:10 -0800 Subject: [PATCH 119/146] hexToBigInt --- .../src/adapters/caip-permission-adapter-middleware.ts | 4 ++-- .../src/adapters/caip-permission-adapter-permittedChains.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 158bda6edba..26db5270106 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -4,7 +4,7 @@ import type { } from '@metamask/network-controller'; import type { Caveat } from '@metamask/permission-controller'; import { providerErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; +import { hexToBigInt, type JsonRpcRequest } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; import { @@ -62,7 +62,7 @@ export async function caipPermissionAdapterMiddleware( const { chainId } = hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - const scope: InternalScopeString = `eip155:${parseInt(chainId, 16)}`; + const scope: InternalScopeString = `eip155:${hexToBigInt(chainId).toString(10)}`; const sessionScopes = getSessionScopes(caveat.value); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts index f56ff36137a..a2dfffa7369 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-permittedChains.ts @@ -1,6 +1,6 @@ import { toHex } from '@metamask/controller-utils'; import type { Hex } from '@metamask/utils'; -import { KnownCaipNamespace } from '@metamask/utils'; +import { hexToBigInt, KnownCaipNamespace } from '@metamask/utils'; import type { Caip25CaveatValue } from '../caip25Permission'; import { getUniqueArrayItems } from '../scope/transform'; @@ -57,7 +57,7 @@ export const addPermittedEthChainId = ( caip25CaveatValue: Caip25CaveatValue, chainId: Hex, ): Caip25CaveatValue => { - const scopeString = `eip155:${parseInt(chainId, 16)}`; + const scopeString = `eip155:${hexToBigInt(chainId).toString(10)}`; if ( Object.keys(caip25CaveatValue.requiredScopes).includes(scopeString) || Object.keys(caip25CaveatValue.optionalScopes).includes(scopeString) From 61c654a4d9a37ba1a87d5535466fa7bd92e07423 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 8 Jan 2025 09:14:37 -0800 Subject: [PATCH 120/146] lint --- .../src/adapters/caip-permission-adapter-middleware.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index 26db5270106..ca73542a001 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -62,7 +62,9 @@ export async function caipPermissionAdapterMiddleware( const { chainId } = hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - const scope: InternalScopeString = `eip155:${hexToBigInt(chainId).toString(10)}`; + const scope: InternalScopeString = `eip155:${hexToBigInt(chainId).toString( + 10, + )}`; const sessionScopes = getSessionScopes(caveat.value); From c1dd11fae3ad63b3a70f312c4781dadc27fb4a1d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 10 Jan 2025 15:53:10 -0600 Subject: [PATCH 121/146] add to MultichainMiddlewareManager description --- .../multichain/src/middlewares/MultichainMiddlewareManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 00ecc733094..9ae20e668f8 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -32,6 +32,9 @@ type MiddlewareEntry = MiddlewareKey & { /** * A helper that facilates registering and calling of provided middleware instances * in the RPC pipeline based on the incoming request's scope, origin, and tabId. + * The core purpose of this class is to enable and manage multichain subscriptions + * (i.e. eth_subscribe called accross different chains and domains). + * * Note that only one middleware instance can be registered per scope, origin, tabId key. */ export class MultichainMiddlewareManager { From 035367254f62b1df39877e212b7e3bdb4e75846d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 10 Jan 2025 14:26:40 -0800 Subject: [PATCH 122/146] remove getSupportedScopes --- packages/multichain/src/scope/filter.test.ts | 74 -------------------- packages/multichain/src/scope/filter.ts | 23 ------ 2 files changed, 97 deletions(-) diff --git a/packages/multichain/src/scope/filter.test.ts b/packages/multichain/src/scope/filter.test.ts index 09877ef59da..8be87ec7983 100644 --- a/packages/multichain/src/scope/filter.test.ts +++ b/packages/multichain/src/scope/filter.test.ts @@ -1,6 +1,5 @@ import * as Assert from './assert'; import { - getSupportedScopes, bucketScopesBySupport, getSupportedScopeObjects, } from './filter'; @@ -20,79 +19,6 @@ jest.mock('./supported', () => ({ const MockSupported = jest.mocked(Supported); describe('filter', () => { - describe('getSupportedScopes', () => { - const isChainIdSupported = jest.fn(); - - it('checks if each scope is supported', () => { - getSupportedScopes( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ); - - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:1', - { - methods: ['a'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - expect(MockAssert.assertScopeSupported).toHaveBeenCalledWith( - 'eip155:5', - { - methods: ['b'], - notifications: [], - accounts: [], - }, - { isChainIdSupported }, - ); - }); - - it('returns only supported scopes', () => { - MockAssert.assertScopeSupported.mockImplementation((scopeString) => { - if (scopeString === 'eip155:1') { - throw new Error('scope not supported'); - } - }); - - expect( - getSupportedScopes( - { - 'eip155:1': { - methods: ['a'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }, - { isChainIdSupported }, - ), - ).toStrictEqual({ - 'eip155:5': { - methods: ['b'], - notifications: [], - accounts: [], - }, - }); - }); - }); - describe('bucketScopesBySupport', () => { const isChainIdSupported = jest.fn(); diff --git a/packages/multichain/src/scope/filter.ts b/packages/multichain/src/scope/filter.ts index 8c4758632d3..0cd9a886620 100644 --- a/packages/multichain/src/scope/filter.ts +++ b/packages/multichain/src/scope/filter.ts @@ -43,29 +43,6 @@ export const bucketScopesBySupport = ( return { supportedScopes, unsupportedScopes }; }; -/** - * Returns a NormalizedScopesObject with only - * scopes that are supported entirely as is. - * @param scopes - The NormalizedScopesObject to filter. - * @param hooks - The hooks. - * @param hooks.isChainIdSupported - A helper that returns true if an eth chainId is currently supported by the wallet. - * @returns a NormalizedScopesObject with only scopes that are currently supported. - */ -export const getSupportedScopes = ( - scopes: NormalizedScopesObject, - { - isChainIdSupported, - }: { - isChainIdSupported: (chainId: Hex) => boolean; - }, -) => { - const { supportedScopes } = bucketScopesBySupport(scopes, { - isChainIdSupported, - }); - - return supportedScopes; -}; - /** * Returns a NormalizedScopeObject with * unsupported methods and notifications removed. From fa5b27f556d9295b864f901403d4ab42ef39154d Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Fri, 10 Jan 2025 16:49:06 -0600 Subject: [PATCH 123/146] improve testing of nested errors in multichainMethodCallValidator (#5131) --- .../multichainMethodCallValidator.test.ts | 172 ++++++++---------- .../multichainMethodCallValidator.ts | 22 +-- 2 files changed, 77 insertions(+), 117 deletions(-) diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts index 72fee461196..3ba8bd4b4a2 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.test.ts @@ -70,26 +70,21 @@ describe('multichainMethodCallValidatorMiddleware', () => { mockNext, (error) => { try { - expect(error).toBeDefined(); - expect((error as JsonRpcError).message).toBe( - 'Invalid method parameter(s).', - ); - expect((error as JsonRpcError).code).toBe(-32602); - expect((error as JsonRpcError).data).toStrictEqual([ - { - code: -32602, - message: 'scope is required, but is undefined', - data: { - param: 'scope', - path: [], - schema: { - pattern: '[-a-z0-9]{3,8}(:[-_a-zA-Z0-9]{1,32})?', - type: 'string', - }, - got: undefined, - }, + const rpcError = error as JsonRpcError & { data: JsonRpcError[] }; + expect(rpcError.message).toBe('Invalid method parameter(s).'); + expect(rpcError.code).toBe(-32602); + expect(rpcError.data[0].data).toStrictEqual({ + got: undefined, + param: 'scope', + path: [], + schema: { + pattern: '[-a-z0-9]{3,8}(:[-_a-zA-Z0-9]{1,32})?', + type: 'string', }, - ]); + }); + expect(rpcError.data[0].message).toBe( + 'scope is required, but is undefined', + ); resolve(); } catch (e) { reject(e); @@ -125,31 +120,26 @@ describe('multichainMethodCallValidatorMiddleware', () => { mockNext, (error) => { try { - expect(error).toBeDefined(); - expect((error as JsonRpcError).message).toBe( - 'Invalid method parameter(s).', - ); - expect((error as JsonRpcError).code).toBe(-32602); - expect((error as JsonRpcError).data).toStrictEqual([ - { - code: -32602, - data: { - got: undefined, - param: 'request', - path: [], - schema: { - properties: { - method: { - type: 'string', - }, - params: true, - }, - type: 'object', + const rpcError = error as JsonRpcError & { data: JsonRpcError[] }; + expect(rpcError.message).toBe('Invalid method parameter(s).'); + expect(rpcError.code).toBe(-32602); + expect(rpcError.data[0].data).toStrictEqual({ + got: undefined, + param: 'request', + path: [], + schema: { + properties: { + method: { + type: 'string', }, + params: true, }, - message: 'request is required, but is undefined', + type: 'object', }, - ]); + }); + expect(rpcError.data[0].message).toBe( + 'request is required, but is undefined', + ); resolve(); } catch (e) { reject(e); @@ -191,30 +181,25 @@ describe('multichainMethodCallValidatorMiddleware', () => { mockNext, (error) => { try { - expect(error).toBeDefined(); - expect((error as JsonRpcError).message).toBe( - 'Invalid method parameter(s).', - ); - expect((error as JsonRpcError).code).toBe(-32602); - expect((error as JsonRpcError).data).toStrictEqual([ - { - code: -32602, - data: { - got: { - method: {}, - params: { - test: 'test', - }, - }, - param: 'request', - path: ['method'], - schema: { - type: 'string', - }, + const rpcError = error as JsonRpcError & { data: JsonRpcError[] }; + expect(rpcError.message).toBe('Invalid method parameter(s).'); + expect(rpcError.code).toBe(-32602); + expect(rpcError.data[0].data).toStrictEqual({ + got: { + method: {}, + params: { + test: 'test', }, - message: 'request.method is not of a type(s) string', }, - ]); + param: 'request', + path: ['method'], + schema: { + type: 'string', + }, + }); + expect(rpcError.data[0].message).toBe( + 'request.method is not of a type(s) string', + ); resolve(); } catch (e) { reject(e); @@ -296,31 +281,26 @@ describe('multichainMethodCallValidatorMiddleware', () => { mockNext, (error) => { try { - expect(error).toBeDefined(); - expect((error as JsonRpcError).code).toBe(-32602); - expect((error as JsonRpcError).message).toBe( - 'Invalid method parameter(s).', - ); - expect((error as JsonRpcError).data).toStrictEqual([ - { - code: -32602, - data: { - got: undefined, - param: 'notification', - path: [], - schema: { - properties: { - method: { - type: 'string', - }, - params: true, - }, - type: 'object', + const rpcError = error as JsonRpcError & { data: JsonRpcError[] }; + expect(rpcError.message).toBe('Invalid method parameter(s).'); + expect(rpcError.code).toBe(-32602); + expect(rpcError.data[0].data).toStrictEqual({ + got: undefined, + param: 'notification', + path: [], + schema: { + properties: { + method: { + type: 'string', }, + params: true, }, - message: 'notification is required, but is undefined', + type: 'object', }, - ]); + }); + expect(rpcError.data[0].message).toBe( + 'notification is required, but is undefined', + ); resolve(); } catch (e) { reject(e); @@ -465,21 +445,15 @@ describe('multichainMethodCallValidatorMiddleware', () => { mockNext, (error) => { try { - expect(error).toBeDefined(); - console.log('error in test', error); - expect((error as JsonRpcError).message).toBe( - 'Invalid method parameter(s).', + const rpcError = error as JsonRpcError & { data: JsonRpcError[] }; + expect(rpcError.message).toBe('Invalid method parameter(s).'); + expect(rpcError.code).toBe(-32602); + expect(rpcError.data[0].data).toStrictEqual({ + method: 'unknown_method', + }); + expect(rpcError.data[0].message).toBe( + 'The method does not exist / is not available.', ); - expect((error as JsonRpcError).code).toBe(-32602); - expect((error as JsonRpcError).data).toStrictEqual([ - { - code: -32601, - message: 'The method does not exist / is not available.', - data: { - method: 'unknown_method', - }, - }, - ]); resolve(); } catch (e) { reject(e); diff --git a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts index 77c23bc1b75..77977930849 100644 --- a/packages/multichain/src/middlewares/multichainMethodCallValidator.ts +++ b/packages/multichain/src/middlewares/multichainMethodCallValidator.ts @@ -24,8 +24,7 @@ const transformError = ( error.path.length > 0 ? `.${error.path.join('.')}` : '' } ${error.message}`; - return { - code: -32602, // TODO: could be a different error code or not wrapped in json-rpc error, since this will also be wrapped in a -32602 invalid params error + return rpcErrors.invalidParams({ message, data: { param: param.name, @@ -33,7 +32,7 @@ const transformError = ( schema: error.schema, got, }, - }; + }); }; const v = new Validator(); @@ -66,26 +65,13 @@ const multichainMethodCallValidator = async ( !isObject(methodToCheck) || !('params' in methodToCheck) ) { - return [ - { - code: -32601, - message: 'The method does not exist / is not available.', - data: { - method, - }, - }, - ]; + return [rpcErrors.methodNotFound({ data: { method } })] as JsonRpcError[]; } const errors: JsonRpcError[] = []; for (const param of methodToCheck.params) { if (!isObject(params)) { - return [ - { - code: -32602, - message: 'Invalid method parameter(s).', - }, - ]; + return [rpcErrors.invalidParams()] as JsonRpcError[]; } const p = param as ContentDescriptorObject; const paramToCheck = params[p.name]; From cf554f835bc83af8c2db56d1b53e6e92a3bbe953 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 10 Jan 2025 15:06:05 -0800 Subject: [PATCH 124/146] yarn dedupe --- yarn.lock | 368 +----------------------------------------------------- 1 file changed, 6 insertions(+), 362 deletions(-) diff --git a/yarn.lock b/yarn.lock index bb67085c500..a20b99aac6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,23 +193,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/code-frame@npm:7.24.7" - dependencies: - "@babel/highlight": "npm:^7.24.7" - picocolors: "npm:^1.0.0" - checksum: 10/4812e94885ba7e3213d49583a155fdffb05292330f0a9b2c41b49288da70cf3c746a3fda0bf1074041a6d741c33f8d7be24be5e96f41ef77395eeddc5c9ff624 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.25.2": - version: 7.25.4 - resolution: "@babel/compat-data@npm:7.25.4" - checksum: 10/d37a8936cc355a9ca3050102e03d179bdae26bd2e5c99a977637376c192b23637a039795f153c849437a086727628c9860e2c6af92d7151396e2362c09176337 - languageName: node - linkType: hard - "@babel/compat-data@npm:^7.25.9": version: 7.26.3 resolution: "@babel/compat-data@npm:7.26.3" @@ -217,30 +200,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.1.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.5, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": - version: 7.25.2 - resolution: "@babel/core@npm:7.25.2" - dependencies: - "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.25.0" - "@babel/helper-compilation-targets": "npm:^7.25.2" - "@babel/helper-module-transforms": "npm:^7.25.2" - "@babel/helpers": "npm:^7.25.0" - "@babel/parser": "npm:^7.25.0" - "@babel/template": "npm:^7.25.0" - "@babel/traverse": "npm:^7.25.2" - "@babel/types": "npm:^7.25.2" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10/0d6ec10ff430df66f654c089d6f7ef1d9bed0c318ac257ad5f0dfa0caa45666011828ae75f998bcdb279763e892b091b2925d0bc483299e61649d2c7a2245e33 - languageName: node - linkType: hard - -"@babel/core@npm:^7.11.6": +"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.5, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": version: 7.26.0 resolution: "@babel/core@npm:7.26.0" dependencies: @@ -263,18 +223,6 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.4": - version: 7.25.5 - resolution: "@babel/generator@npm:7.25.5" - dependencies: - "@babel/types": "npm:^7.25.4" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^2.5.1" - checksum: 10/e6d046afe739cfa706c40c127b7436731acb2a3146d408a7d89dbf16448491b35bc09b7d285cc19c2c1f8980d74b5a99df200d67c859bb5260986614685b0770 - languageName: node - linkType: hard - "@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.3, @babel/generator@npm:^7.7.2": version: 7.26.3 resolution: "@babel/generator@npm:7.26.3" @@ -297,19 +245,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-compilation-targets@npm:7.25.2" - dependencies: - "@babel/compat-data": "npm:^7.25.2" - "@babel/helper-validator-option": "npm:^7.24.8" - browserslist: "npm:^4.23.1" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10/eccb2d75923d2d4d596f9ff64716e8664047c4192f1b44c7d5c07701d4a3498ac2587a72ddae1046e65a501bc630eb7df4557958b08ec2dcf5b4a264a052f111 - languageName: node - linkType: hard - "@babel/helper-compilation-targets@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-compilation-targets@npm:7.25.9" @@ -350,16 +285,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-module-imports@npm:7.24.7" - dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10/df8bfb2bb18413aa151ecd63b7d5deb0eec102f924f9de6bc08022ced7ed8ca7fed914562d2f6fa5b59b74a5d6e255dc35612b2bc3b8abf361e13f61b3704770 - languageName: node - linkType: hard - "@babel/helper-module-imports@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-module-imports@npm:7.25.9" @@ -383,20 +308,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-module-transforms@npm:7.25.2" - dependencies: - "@babel/helper-module-imports": "npm:^7.24.7" - "@babel/helper-simple-access": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.2" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/a3bcf7815f3e9d8b205e0af4a8d92603d685868e45d119b621357e274996bf916216bb95ab5c6a60fde3775b91941555bf129d608e3d025b04f8aac84589f300 - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" @@ -446,13 +357,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-string-parser@npm:7.24.8" - checksum: 10/6d1bf8f27dd725ce02bdc6dffca3c95fb9ab8a06adc2edbd9c1c9d68500274230d1a609025833ed81981eff560045b6b38f7b4c6fb1ab19fc90e5004e3932535 - languageName: node - linkType: hard - "@babel/helper-string-parser@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-string-parser@npm:7.25.9" @@ -460,13 +364,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-validator-identifier@npm:7.24.7" - checksum: 10/86875063f57361471b531dbc2ea10bbf5406e12b06d249b03827d361db4cad2388c6f00936bcd9dc86479f7e2c69ea21412c2228d4b3672588b754b70a449d4b - languageName: node - linkType: hard - "@babel/helper-validator-identifier@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-identifier@npm:7.25.9" @@ -481,23 +378,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-validator-option@npm:7.24.8" - checksum: 10/a52442dfa74be6719c0608fee3225bd0493c4057459f3014681ea1a4643cd38b68ff477fe867c4b356da7330d085f247f0724d300582fa4ab9a02efaf34d107c - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helpers@npm:7.25.0" - dependencies: - "@babel/template": "npm:^7.25.0" - "@babel/types": "npm:^7.25.0" - checksum: 10/4fcb8167eba9853e30b8b235b81b923ef7b707396b0e23d7a4fa3e811729506755576cb9ec736e8b92cf19e5a1ec61e83d182904d8e6a0953803c6bebc2e1592 - languageName: node - linkType: hard - "@babel/helpers@npm:^7.26.0": version: 7.26.0 resolution: "@babel/helpers@npm:7.26.0" @@ -508,18 +388,6 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/highlight@npm:7.24.7" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.24.7" - chalk: "npm:^2.4.2" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.0.0" - checksum: 10/69b73f38cdd4f881b09b939a711e76646da34f4834f4ce141d7a49a6bb1926eab1c594148970a8aa9360398dff800f63aade4e81fafdd7c8d8a8489ea93bfec1 - languageName: node - linkType: hard - "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.3": version: 7.26.3 resolution: "@babel/parser@npm:7.26.3" @@ -531,17 +399,6 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/parser@npm:7.25.4" - dependencies: - "@babel/types": "npm:^7.25.4" - bin: - parser: ./bin/babel-parser.js - checksum: 10/343b8a76c43549e370fe96f4f6d564382a6cdff60e9c3b8a594c51e4cefd58ec9945e82e8c4dfbf15ac865a04e4b29806531440760748e28568e6aec21bc9cb5 - languageName: node - linkType: hard - "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -781,17 +638,6 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/template@npm:7.25.0" - dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/parser": "npm:^7.25.0" - "@babel/types": "npm:^7.25.0" - checksum: 10/07ebecf6db8b28244b7397628e09c99e7a317b959b926d90455c7253c88df3677a5a32d1501d9749fe292a263ff51a4b6b5385bcabd5dadd3a48036f4d4949e0 - languageName: node - linkType: hard - "@babel/template@npm:^7.25.9, @babel/template@npm:^7.3.3": version: 7.25.9 resolution: "@babel/template@npm:7.25.9" @@ -818,21 +664,6 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.25.2": - version: 7.25.4 - resolution: "@babel/traverse@npm:7.25.4" - dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.25.4" - "@babel/parser": "npm:^7.25.4" - "@babel/template": "npm:^7.25.0" - "@babel/types": "npm:^7.25.4" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10/a85c16047ab8e454e2e758c75c31994cec328bd6d8b4b22e915fa7393a03b3ab96d1218f43dc7ef77c957cc488dc38100bdf504d08a80a131e89b2e49cfa2be5 - languageName: node - linkType: hard - "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.3, @babel/types@npm:^7.3.3": version: 7.26.3 resolution: "@babel/types@npm:7.26.3" @@ -843,17 +674,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/types@npm:7.25.4" - dependencies: - "@babel/helper-string-parser": "npm:^7.24.8" - "@babel/helper-validator-identifier": "npm:^7.24.7" - to-fast-properties: "npm:^2.0.0" - checksum: 10/d4a1194612d0a2a6ce9a0be325578b43d74e5f5278c67409468ba0a924341f0ad349ef0245ee8a36da3766efe5cc59cd6bb52547674150f97d8dc4c8cfa5d6b8 - languageName: node - linkType: hard - "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -915,7 +735,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.4.1": +"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.4.1": version: 4.4.1 resolution: "@eslint-community/eslint-utils@npm:4.4.1" dependencies: @@ -926,17 +746,6 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" - dependencies: - eslint-visitor-keys: "npm:^3.3.0" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10/8d70bcdcd8cd279049183aca747d6c2ed7092a5cf0cf5916faac1ef37ffa74f0c245c2a3a3d3b9979d9dfdd4ca59257b4c5621db699d637b847a2c5e02f491c2 - languageName: node - linkType: hard - "@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.11.0, @eslint-community/regexpp@npm:^4.12.1": version: 4.12.1 resolution: "@eslint-community/regexpp@npm:4.12.1" @@ -3487,19 +3296,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/keyring-internal-api@npm:^1.0.0": - version: 1.0.0 - resolution: "@metamask/keyring-internal-api@npm:1.0.0" - dependencies: - "@metamask/keyring-api": "npm:^12.0.0" - "@metamask/keyring-utils": "npm:^1.0.0" - "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^9.3.0" - checksum: 10/dd0fff93ddfdce008f1db82d404bd040d09840413723c831819d3a7f4c2819a4303657e4acd7578cfd22bd05ad9c7aa563fc88f13f2f06999e2325ada71b824c - languageName: node - linkType: hard - -"@metamask/keyring-internal-api@npm:^1.1.0": +"@metamask/keyring-internal-api@npm:^1.0.0, @metamask/keyring-internal-api@npm:^1.1.0": version: 1.1.0 resolution: "@metamask/keyring-internal-api@npm:1.1.0" dependencies: @@ -4188,20 +3985,7 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-sdk@npm:^6.10.0, @metamask/snaps-sdk@npm:^6.7.0": - version: 6.10.0 - resolution: "@metamask/snaps-sdk@npm:6.10.0" - dependencies: - "@metamask/key-tree": "npm:^9.1.2" - "@metamask/providers": "npm:^18.1.1" - "@metamask/rpc-errors": "npm:^7.0.1" - "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^10.0.0" - checksum: 10/02f04536328a64ff1e9e48fb6b109698d6d83f42af5666a9758ccb1e7a1e67c0c2e296ef2fef419dd3d1c8f26bbf30b9f31911a1baa66f044f21cd0ecb7a11a7 - languageName: node - linkType: hard - -"@metamask/snaps-sdk@npm:^6.11.0": +"@metamask/snaps-sdk@npm:^6.10.0, @metamask/snaps-sdk@npm:^6.11.0, @metamask/snaps-sdk@npm:^6.7.0": version: 6.11.0 resolution: "@metamask/snaps-sdk@npm:6.11.0" dependencies: @@ -6138,16 +5922,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1": - version: 8.12.1 - resolution: "acorn@npm:8.12.1" - bin: - acorn: bin/acorn - checksum: 10/d08c2d122bba32d0861e0aa840b2ee25946c286d5dc5990abca991baf8cdbfbe199b05aacb221b979411a2fea36f83e26b5ac4f6b4e0ce49038c62316c1848f0 - languageName: node - linkType: hard - -"acorn@npm:^8.14.0": +"acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1": version: 8.14.0 resolution: "acorn@npm:8.14.0" bin: @@ -6270,15 +6045,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^3.2.1": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" - dependencies: - color-convert: "npm:^1.9.0" - checksum: 10/d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 - languageName: node - linkType: hard - "ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" @@ -6765,20 +6531,6 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.23.1": - version: 4.23.3 - resolution: "browserslist@npm:4.23.3" - dependencies: - caniuse-lite: "npm:^1.0.30001646" - electron-to-chromium: "npm:^1.5.4" - node-releases: "npm:^2.0.18" - update-browserslist-db: "npm:^1.1.0" - bin: - browserslist: cli.js - checksum: 10/e266d18c6c6c5becf9a1a7aa264477677b9796387972e8fce34854bb33dc1666194dc28389780e5dc6566e68a95e87ece2ce222e1c4ca93c2b75b61dfebd5f1c - languageName: node - linkType: hard - "browserslist@npm:^4.24.0": version: 4.24.4 resolution: "browserslist@npm:4.24.4" @@ -6948,13 +6700,6 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001646": - version: 1.0.30001653 - resolution: "caniuse-lite@npm:1.0.30001653" - checksum: 10/cd9b1c0fe03249e593789a11a9ef14f987b385e60441748945916b19e74e7bc5c82c40d4836496a647586651898741aed1598ae0792114a9f0d7d7fdb2b7deb0 - languageName: node - linkType: hard - "caniuse-lite@npm:^1.0.30001688": version: 1.0.30001690 resolution: "caniuse-lite@npm:1.0.30001690" @@ -6969,17 +6714,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.4.2": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: "npm:^3.2.1" - escape-string-regexp: "npm:^1.0.5" - supports-color: "npm:^5.3.0" - checksum: 10/3d1d103433166f6bfe82ac75724951b33769675252d8417317363ef9d54699b7c3b2d46671b772b893a8e50c3ece70c4b933c73c01e81bc60ea4df9b55afa303 - languageName: node - linkType: hard - "chalk@npm:^3.0.0": version: 3.0.0 resolution: "chalk@npm:3.0.0" @@ -7192,15 +6926,6 @@ __metadata: languageName: node linkType: hard -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: "npm:1.1.3" - checksum: 10/ffa319025045f2973919d155f25e7c00d08836b6b33ea2d205418c59bd63a665d713c52d9737a9e0fe467fb194b40fbef1d849bae80d674568ee220a31ef3d10 - languageName: node - linkType: hard - "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -7210,13 +6935,6 @@ __metadata: languageName: node linkType: hard -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 10/09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d - languageName: node - linkType: hard - "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" @@ -7709,13 +7427,6 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.4": - version: 1.5.13 - resolution: "electron-to-chromium@npm:1.5.13" - checksum: 10/b3de6dbca66e399eacd4f7e2b7603394c8949c9e724d838a45e092725005ff435aabfbf00f738e45451eb23147684f7f9251a5ed75619a539642b2bccea20b45 - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.5.73": version: 1.5.79 resolution: "electron-to-chromium@npm:1.5.79" @@ -7857,13 +7568,6 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.2": - version: 3.1.2 - resolution: "escalade@npm:3.1.2" - checksum: 10/a1e07fea2f15663c30e40b9193d658397846ffe28ce0a3e4da0d8e485fedfeca228ab846aee101a05015829adf39f9934ff45b2a3fca47bed37a29646bd05cd3 - languageName: node - linkType: hard - "escape-html@npm:^1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -7871,13 +7575,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 10/6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 - languageName: node - linkType: hard - "escape-string-regexp@npm:^2.0.0": version: 2.0.0 resolution: "escape-string-regexp@npm:2.0.0" @@ -8102,7 +7799,7 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.3": +"eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 10/3f357c554a9ea794b094a09bd4187e5eacd1bc0d0653c3adeb87962c548e6a1ab8f982b86963ae1337f5d976004146536dcee5d0e2806665b193fbfbf1a9231b @@ -9097,13 +8794,6 @@ __metadata: languageName: node linkType: hard -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 10/4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b - languageName: node - linkType: hard - "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" @@ -10542,15 +10232,6 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^2.5.1": - version: 2.5.2 - resolution: "jsesc@npm:2.5.2" - bin: - jsesc: bin/jsesc - checksum: 10/d2096abdcdec56969764b40ffc91d4a23408aa2f351b4d1c13f736f25476643238c43fdbaf38a191c26b1b78fd856d965f5d4d0dde7b89459cd94025190cdf13 - languageName: node - linkType: hard - "jsesc@npm:^3.0.2": version: 3.1.0 resolution: "jsesc@npm:3.1.0" @@ -11292,13 +10973,6 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.18": - version: 2.0.18 - resolution: "node-releases@npm:2.0.18" - checksum: 10/241e5fa9556f1c12bafb83c6c3e94f8cf3d8f2f8f904906ecef6e10bcaa1d59aa61212d4651bec70052015fc54bd3fdcdbe7fc0f638a17e6685aa586c076ec4e - languageName: node - linkType: hard - "node-releases@npm:^2.0.19": version: 2.0.19 resolution: "node-releases@npm:2.0.19" @@ -12974,15 +12648,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^5.3.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: "npm:^3.0.0" - checksum: 10/5f505c6fa3c6e05873b43af096ddeb22159831597649881aeb8572d6fe3b81e798cc10840d0c9735e0026b250368851b7f77b65e84f4e4daa820a4f69947f55b - languageName: node - linkType: hard - "supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -13161,13 +12826,6 @@ __metadata: languageName: node linkType: hard -"to-fast-properties@npm:^2.0.0": - version: 2.0.0 - resolution: "to-fast-properties@npm:2.0.0" - checksum: 10/be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -13508,20 +13166,6 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.0": - version: 1.1.0 - resolution: "update-browserslist-db@npm:1.1.0" - dependencies: - escalade: "npm:^3.1.2" - picocolors: "npm:^1.0.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10/d70b9efeaf4601aadb1a4f6456a7a5d9118e0063d995866b8e0c5e0cf559482671dab6ce7b079f9536b06758a344fbd83f974b965211e1c6e8d1958540b0c24c - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.1.1": version: 1.1.2 resolution: "update-browserslist-db@npm:1.1.2" From d07f3725df31a2dc68afa0e90b47f098c675a69d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Mon, 13 Jan 2025 08:35:37 -0800 Subject: [PATCH 125/146] remove cross-spawn resolution --- package.json | 3 --- yarn.lock | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 026e992e1c4..2dade0cfa01 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,6 @@ "pre-push": "yarn lint" }, "resolutions": { - "cross-spawn@^7.0.0": "^7.0.5", - "cross-spawn@^7.0.2": "^7.0.5", - "cross-spawn@^7.0.3": "^7.0.5", "elliptic@6.5.4": "^6.5.7", "fast-xml-parser@^4.3.4": "^4.4.1", "ws@7.4.6": "^7.5.10" diff --git a/yarn.lock b/yarn.lock index a20b99aac6e..5605785ee12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7130,7 +7130,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.5, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: From 07d969c6c4e1f79224890736d948a465b095ebf4 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 14 Jan 2025 11:03:55 -0800 Subject: [PATCH 126/146] Replace revokePermission hook with revokePermissionForOrigin bound hook --- .../src/handlers/wallet-revokeSession.test.ts | 23 +++++++++---------- .../src/handlers/wallet-revokeSession.ts | 6 ++--- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-revokeSession.test.ts b/packages/multichain/src/handlers/wallet-revokeSession.test.ts index e11b89f42c2..c74c95a1f7c 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.test.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.test.ts @@ -19,7 +19,7 @@ const baseRequest: JsonRpcRequest & { origin: string } = { const createMockedHandler = () => { const next = jest.fn(); const end = jest.fn(); - const revokePermission = jest.fn(); + const revokePermissionForOrigin = jest.fn(); const response = { result: true, id: 1, @@ -27,32 +27,31 @@ const createMockedHandler = () => { }; const handler = (request: JsonRpcRequest & { origin: string }) => walletRevokeSession.implementation(request, response, next, end, { - revokePermission, + revokePermissionForOrigin, }); return { next, response, end, - revokePermission, + revokePermissionForOrigin, handler, }; }; describe('wallet_revokeSession', () => { it('revokes the the CAIP-25 endowment permission', async () => { - const { handler, revokePermission } = createMockedHandler(); + const { handler, revokePermissionForOrigin } = createMockedHandler(); await handler(baseRequest); - expect(revokePermission).toHaveBeenCalledWith( - 'http://test.com', + expect(revokePermissionForOrigin).toHaveBeenCalledWith( Caip25EndowmentPermissionName, ); }); it('returns true if the CAIP-25 endowment permission does not exist', async () => { - const { handler, response, revokePermission } = createMockedHandler(); - revokePermission.mockImplementation(() => { + const { handler, response, revokePermissionForOrigin } = createMockedHandler(); + revokePermissionForOrigin.mockImplementation(() => { throw new PermissionDoesNotExistError( 'foo.com', Caip25EndowmentPermissionName, @@ -64,8 +63,8 @@ describe('wallet_revokeSession', () => { }); it('returns true if the subject does not exist', async () => { - const { handler, response, revokePermission } = createMockedHandler(); - revokePermission.mockImplementation(() => { + const { handler, response, revokePermissionForOrigin } = createMockedHandler(); + revokePermissionForOrigin.mockImplementation(() => { throw new UnrecognizedSubjectError('foo.com'); }); @@ -74,8 +73,8 @@ describe('wallet_revokeSession', () => { }); it('throws an internal RPC error if something unexpected goes wrong with revoking the permission', async () => { - const { handler, revokePermission, end } = createMockedHandler(); - revokePermission.mockImplementation(() => { + const { handler, revokePermissionForOrigin, end } = createMockedHandler(); + revokePermissionForOrigin.mockImplementation(() => { throw new Error('revoke failed'); }); diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 6bc628cf30f..60215786217 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -23,7 +23,7 @@ import { Caip25EndowmentPermissionName } from '../caip25Permission'; * @param _next - The next middleware function. Unused. * @param end - The end callback function. * @param hooks - The hooks object. - * @param hooks.revokePermission - The hook for revoking a permission for an origin function. + * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function. */ async function walletRevokeSessionHandler( request: JsonRpcRequest & { origin: string }, @@ -31,11 +31,11 @@ async function walletRevokeSessionHandler( _next: JsonRpcEngineNextCallback, end: JsonRpcEngineEndCallback, hooks: { - revokePermission: (origin: string, permissionName: string) => void; + revokePermissionForOrigin: (permissionName: string) => void; }, ) { try { - hooks.revokePermission(request.origin, Caip25EndowmentPermissionName); + hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName); } catch (err) { if ( !(err instanceof UnrecognizedSubjectError) && From e05b7d3ec563b3a7f2c24198fbffc3acf1191ec0 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 14 Jan 2025 11:17:03 -0800 Subject: [PATCH 127/146] replace getCaveat with getCaveatForOrigin --- .../src/handlers/wallet-getSession.test.ts | 15 +++++++-------- .../src/handlers/wallet-getSession.ts | 10 ++++------ .../src/handlers/wallet-invokeMethod.test.ts | 19 +++++++++---------- .../src/handlers/wallet-invokeMethod.ts | 10 ++++------ 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/packages/multichain/src/handlers/wallet-getSession.test.ts b/packages/multichain/src/handlers/wallet-getSession.test.ts index 965f5ec30f6..206f706eb0f 100644 --- a/packages/multichain/src/handlers/wallet-getSession.test.ts +++ b/packages/multichain/src/handlers/wallet-getSession.test.ts @@ -25,7 +25,7 @@ const baseRequest: JsonRpcRequest & { origin: string } = { const createMockedHandler = () => { const next = jest.fn(); const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ + const getCaveatForOrigin = jest.fn().mockReturnValue({ value: { requiredScopes: { 'eip155:1': { @@ -54,33 +54,32 @@ const createMockedHandler = () => { }; const handler = (request: JsonRpcRequest & { origin: string }) => walletGetSession.implementation(request, response, next, end, { - getCaveat, + getCaveatForOrigin, }); return { next, response, end, - getCaveat, + getCaveatForOrigin, handler, }; }; describe('wallet_getSession', () => { it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const { handler, getCaveat } = createMockedHandler(); + const { handler, getCaveatForOrigin } = createMockedHandler(); await handler(baseRequest); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', + expect(getCaveatForOrigin).toHaveBeenCalledWith( Caip25EndowmentPermissionName, Caip25CaveatType, ); }); it('returns empty scopes if the CAIP-25 endowment permission does not exist', async () => { - const { handler, response, getCaveat } = createMockedHandler(); - getCaveat.mockImplementation(() => { + const { handler, response, getCaveatForOrigin } = createMockedHandler(); + getCaveatForOrigin.mockImplementation(() => { throw new Error('permission not found'); }); diff --git a/packages/multichain/src/handlers/wallet-getSession.ts b/packages/multichain/src/handlers/wallet-getSession.ts index cf2d6d2136e..bf343495091 100644 --- a/packages/multichain/src/handlers/wallet-getSession.ts +++ b/packages/multichain/src/handlers/wallet-getSession.ts @@ -20,7 +20,7 @@ import { * @param _next - The next middleware function. Unused. * @param end - The end function. * @param hooks - The hooks object. - * @param hooks.getCaveat - Function to retrieve a caveat. + * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin. */ async function walletGetSessionHandler( request: JsonRpcRequest & { origin: string }, @@ -28,8 +28,7 @@ async function walletGetSessionHandler( _next: () => void, end: () => void, hooks: { - getCaveat: ( - origin: string, + getCaveatForOrigin: ( endowmentPermissionName: string, caveatType: string, ) => Caveat; @@ -37,8 +36,7 @@ async function walletGetSessionHandler( ) { let caveat; try { - caveat = hooks.getCaveat( - request.origin, + caveat = hooks.getCaveatForOrigin( Caip25EndowmentPermissionName, Caip25CaveatType, ); @@ -61,6 +59,6 @@ export const walletGetSession = { methodNames: ['wallet_getSession'], implementation: walletGetSessionHandler, hookNames: { - getCaveat: true, + getCaveatForOrigin: true, }, }; diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts index bbaa990a073..ae7da846565 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.test.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.test.ts @@ -34,7 +34,7 @@ const createMockedRequest = () => ({ const createMockedHandler = () => { const next = jest.fn(); const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ + const getCaveatForOrigin = jest.fn().mockReturnValue({ value: { requiredScopes: { 'eip155:1': { @@ -66,7 +66,7 @@ const createMockedHandler = () => { next, end, { - getCaveat, + getCaveatForOrigin, findNetworkClientIdByChainId, getSelectedNetworkClientId, }, @@ -75,7 +75,7 @@ const createMockedHandler = () => { return { next, end, - getCaveat, + getCaveatForOrigin, findNetworkClientIdByChainId, getSelectedNetworkClientId, handler, @@ -110,10 +110,9 @@ describe('wallet_invokeMethod', () => { it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { const request = createMockedRequest(); - const { handler, getCaveat } = createMockedHandler(); + const { handler, getCaveatForOrigin } = createMockedHandler(); await handler(request); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', + expect(getCaveatForOrigin).toHaveBeenCalledWith( Caip25EndowmentPermissionName, Caip25CaveatType, ); @@ -148,8 +147,8 @@ describe('wallet_invokeMethod', () => { it('throws an unauthorized error when there is no CAIP-25 endowment permission', async () => { const request = createMockedRequest(); - const { handler, getCaveat, end } = createMockedHandler(); - getCaveat.mockImplementation(() => { + const { handler, getCaveatForOrigin, end } = createMockedHandler(); + getCaveatForOrigin.mockImplementation(() => { throw new Error('permission not found'); }); await handler(request); @@ -158,8 +157,8 @@ describe('wallet_invokeMethod', () => { it('throws an unauthorized error when the CAIP-25 endowment permission was not granted from the multichain flow', async () => { const request = createMockedRequest(); - const { handler, getCaveat, end } = createMockedHandler(); - getCaveat.mockReturnValue({ + const { handler, getCaveatForOrigin, end } = createMockedHandler(); + getCaveatForOrigin.mockReturnValue({ value: { isMultichainOrigin: false, }, diff --git a/packages/multichain/src/handlers/wallet-invokeMethod.ts b/packages/multichain/src/handlers/wallet-invokeMethod.ts index 7c9a9ae496e..cc2e8cf0b03 100644 --- a/packages/multichain/src/handlers/wallet-invokeMethod.ts +++ b/packages/multichain/src/handlers/wallet-invokeMethod.ts @@ -37,7 +37,7 @@ export type WalletInvokeMethodRequest = JsonRpcRequest & { * @param next - The next middleware function. * @param end - The end function. * @param hooks - The hooks object. - * @param hooks.getCaveat - the hook for getting a caveat from a permission for an origin. + * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin. * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId. * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId. */ @@ -47,8 +47,7 @@ async function walletInvokeMethodHandler( next: () => void, end: (error: Error) => void, hooks: { - getCaveat: ( - origin: string, + getCaveatForOrigin: ( endowmentPermissionName: string, caveatType: string, ) => Caveat; @@ -62,8 +61,7 @@ async function walletInvokeMethodHandler( let caveat; try { - caveat = hooks.getCaveat( - request.origin, + caveat = hooks.getCaveatForOrigin( Caip25EndowmentPermissionName, Caip25CaveatType, ); @@ -122,7 +120,7 @@ export const walletInvokeMethod = { methodNames: ['wallet_invokeMethod'], implementation: walletInvokeMethodHandler, hookNames: { - getCaveat: true, + getCaveatForOrigin: true, findNetworkClientIdByChainId: true, getSelectedNetworkClientId: true, }, From 10158bd0ea579843d2682cce6aebe9f3e3945010 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 14 Jan 2025 12:50:03 -0800 Subject: [PATCH 128/146] replace getCaveat with getCaveatForOrigin (missed one) --- ...caip-permission-adapter-middleware.test.ts | 19 +++++++++---------- .../caip-permission-adapter-middleware.ts | 7 +++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts index c044c73b0f0..fd47f4107b9 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts @@ -21,7 +21,7 @@ const baseRequest = { const createMockedHandler = () => { const next = jest.fn(); const end = jest.fn(); - const getCaveat = jest.fn().mockReturnValue({ + const getCaveatForOrigin = jest.fn().mockReturnValue({ value: { requiredScopes: { 'eip155:1': { @@ -74,14 +74,14 @@ const createMockedHandler = () => { }, ) => caipPermissionAdapterMiddleware(request, {}, next, end, { - getCaveat, + getCaveatForOrigin, getNetworkConfigurationByNetworkClientId, }); return { next, end, - getCaveat, + getCaveatForOrigin, getNetworkConfigurationByNetworkClientId, handler, }; @@ -89,18 +89,17 @@ const createMockedHandler = () => { describe('CaipPermissionAdapterMiddleware', () => { it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const { handler, getCaveat } = createMockedHandler(); + const { handler, getCaveatForOrigin } = createMockedHandler(); await handler(baseRequest); - expect(getCaveat).toHaveBeenCalledWith( - 'http://test.com', + expect(getCaveatForOrigin).toHaveBeenCalledWith( Caip25EndowmentPermissionName, Caip25CaveatType, ); }); it('allows the request when there is no CAIP-25 endowment permission', async () => { - const { handler, getCaveat, next } = createMockedHandler(); - getCaveat.mockImplementation(() => { + const { handler, getCaveatForOrigin, next } = createMockedHandler(); + getCaveatForOrigin.mockImplementation(() => { throw new Error('permission not found'); }); await handler(baseRequest); @@ -108,8 +107,8 @@ describe('CaipPermissionAdapterMiddleware', () => { }); it('allows the request when the CAIP-25 endowment permission was not granted from the multichain API', async () => { - const { handler, getCaveat, next } = createMockedHandler(); - getCaveat.mockReturnValue({ + const { handler, getCaveatForOrigin, next } = createMockedHandler(); + getCaveatForOrigin.mockReturnValue({ value: { isMultichainOrigin: false, }, diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts index ca73542a001..3d258a45fe1 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts @@ -23,7 +23,7 @@ import { getSessionScopes } from './caip-permission-adapter-session-scopes'; * @param next - The next middleware function. * @param end - The end function. * @param hooks - The hooks object. - * @param hooks.getCaveat - Function to retrieve a caveat. + * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin. * @param hooks.getNetworkConfigurationByNetworkClientId - Function to retrieve a network configuration. */ export async function caipPermissionAdapterMiddleware( @@ -35,7 +35,7 @@ export async function caipPermissionAdapterMiddleware( next: () => Promise, end: (error?: Error) => void, hooks: { - getCaveat: ( + getCaveatForOrigin: ( ...args: unknown[] ) => Caveat; getNetworkConfigurationByNetworkClientId: ( @@ -47,8 +47,7 @@ export async function caipPermissionAdapterMiddleware( let caveat; try { - caveat = hooks.getCaveat( - request.origin, + caveat = hooks.getCaveatForOrigin( Caip25EndowmentPermissionName, Caip25CaveatType, ); From b57d7063bc06d81ddf15c7cb3d99df6fb414b203 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 14 Jan 2025 14:42:37 -0800 Subject: [PATCH 129/146] Fix wallet-revokeSession hookNames --- packages/multichain/src/handlers/wallet-revokeSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/handlers/wallet-revokeSession.ts b/packages/multichain/src/handlers/wallet-revokeSession.ts index 60215786217..46878cac016 100644 --- a/packages/multichain/src/handlers/wallet-revokeSession.ts +++ b/packages/multichain/src/handlers/wallet-revokeSession.ts @@ -53,6 +53,6 @@ export const walletRevokeSession = { methodNames: ['wallet_revokeSession'], implementation: walletRevokeSessionHandler, hookNames: { - revokePermission: true, + revokePermissionForOrigin: true, }, }; From 93683d1950b5354baa7b449d0d495e1f9e3bf9d2 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 14 Jan 2025 16:00:18 -0800 Subject: [PATCH 130/146] update thresholds --- eslint-warning-thresholds.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/eslint-warning-thresholds.json b/eslint-warning-thresholds.json index fc7d2173b69..5de1f036ef7 100644 --- a/eslint-warning-thresholds.json +++ b/eslint-warning-thresholds.json @@ -2,16 +2,15 @@ "@typescript-eslint/consistent-type-exports": 19, "@typescript-eslint/no-base-to-string": 3, "@typescript-eslint/no-duplicate-enum-values": 2, - "@typescript-eslint/no-misused-promises": 3, - "@typescript-eslint/no-unsafe-enum-comparison": 59, + "@typescript-eslint/no-unsafe-enum-comparison": 34, "@typescript-eslint/no-unused-vars": 36, "@typescript-eslint/prefer-promise-reject-errors": 13, "@typescript-eslint/prefer-readonly": 145, - "@typescript-eslint/switch-exhaustiveness-check": 10, + "@typescript-eslint/switch-exhaustiveness-check": 9, "import-x/namespace": 189, "import-x/no-named-as-default": 1, "import-x/no-named-as-default-member": 8, - "import-x/order": 209, + "import-x/order": 205, "jest/no-conditional-in-test": 129, "jest/prefer-lowercase-title": 2, "jest/prefer-strict-equal": 2, From 1a87b4dd3c8c6f73bc83eebf3c412c9247d4ffad Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 15 Jan 2025 10:57:12 -0800 Subject: [PATCH 131/146] remove adapter middleware --- ...caip-permission-adapter-middleware.test.ts | 147 ------------------ .../caip-permission-adapter-middleware.ts | 80 ---------- packages/multichain/src/index.ts | 1 - 3 files changed, 228 deletions(-) delete mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts delete mode 100644 packages/multichain/src/adapters/caip-permission-adapter-middleware.ts diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts deleted file mode 100644 index fd47f4107b9..00000000000 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { providerErrors } from '@metamask/rpc-errors'; -import type { JsonRpcRequest } from '@metamask/utils'; - -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { caipPermissionAdapterMiddleware } from './caip-permission-adapter-middleware'; - -const baseRequest = { - id: 1, - jsonrpc: '2.0' as const, - origin: 'http://test.com', - networkClientId: 'mainnet', - method: 'eth_call', - params: { - foo: 'bar', - }, -}; - -const createMockedHandler = () => { - const next = jest.fn(); - const end = jest.fn(); - const getCaveatForOrigin = jest.fn().mockReturnValue({ - value: { - requiredScopes: { - 'eip155:1': { - methods: ['eth_call'], - notifications: [], - accounts: [], - }, - 'eip155:5': { - methods: ['eth_chainId'], - notifications: [], - accounts: [], - }, - }, - optionalScopes: { - 'eip155:1': { - methods: ['net_version'], - notifications: [], - accounts: [], - }, - wallet: { - methods: ['wallet_watchAsset'], - notifications: [], - accounts: [], - }, - unhandled: { - methods: ['foobar'], - notifications: [], - accounts: [], - }, - }, - isMultichainOrigin: true, - }, - }); - const getNetworkConfigurationByNetworkClientId = jest - .fn() - .mockImplementation((networkClientId: string) => { - const chainId = - { - mainnet: '0x1', - goerli: '0x5', - }[networkClientId] || '0x999'; - return { - chainId, - }; - }); - const handler = ( - request: JsonRpcRequest & { - networkClientId: string; - origin: string; - }, - ) => - caipPermissionAdapterMiddleware(request, {}, next, end, { - getCaveatForOrigin, - getNetworkConfigurationByNetworkClientId, - }); - - return { - next, - end, - getCaveatForOrigin, - getNetworkConfigurationByNetworkClientId, - handler, - }; -}; - -describe('CaipPermissionAdapterMiddleware', () => { - it('gets the authorized scopes from the CAIP-25 endowment permission', async () => { - const { handler, getCaveatForOrigin } = createMockedHandler(); - await handler(baseRequest); - expect(getCaveatForOrigin).toHaveBeenCalledWith( - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - }); - - it('allows the request when there is no CAIP-25 endowment permission', async () => { - const { handler, getCaveatForOrigin, next } = createMockedHandler(); - getCaveatForOrigin.mockImplementation(() => { - throw new Error('permission not found'); - }); - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - - it('allows the request when the CAIP-25 endowment permission was not granted from the multichain API', async () => { - const { handler, getCaveatForOrigin, next } = createMockedHandler(); - getCaveatForOrigin.mockReturnValue({ - value: { - isMultichainOrigin: false, - }, - }); - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - - it('gets the chainId for the request networkClientId', async () => { - const { handler, getNetworkConfigurationByNetworkClientId } = - createMockedHandler(); - await handler(baseRequest); - expect(getNetworkConfigurationByNetworkClientId).toHaveBeenCalledWith( - 'mainnet', - ); - }); - - describe('when the CAIP-25 endowment permission was granted over the multichain API', () => { - it('throws an error if the requested method is not authorized for the scope specified in the request', async () => { - const { handler, end } = createMockedHandler(); - - await handler({ - ...baseRequest, - method: 'unauthorized_method', - }); - expect(end).toHaveBeenCalledWith(providerErrors.unauthorized()); - }); - - it('allows the request if the requested scope method is authorized in the current scope', async () => { - const { handler, next } = createMockedHandler(); - - await handler(baseRequest); - expect(next).toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts b/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts deleted file mode 100644 index 3d258a45fe1..00000000000 --- a/packages/multichain/src/adapters/caip-permission-adapter-middleware.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { - NetworkConfiguration, - NetworkClientId, -} from '@metamask/network-controller'; -import type { Caveat } from '@metamask/permission-controller'; -import { providerErrors } from '@metamask/rpc-errors'; -import { hexToBigInt, type JsonRpcRequest } from '@metamask/utils'; - -import type { Caip25CaveatValue } from '../caip25Permission'; -import { - Caip25CaveatType, - Caip25EndowmentPermissionName, -} from '../caip25Permission'; -import { Eip1193OnlyMethods, KnownWalletScopeString } from '../scope/constants'; -import type { InternalScopeString } from '../scope/types'; -import { getSessionScopes } from './caip-permission-adapter-session-scopes'; - -/** - * Middleware to handle CAIP-25 permission requests. - * - * @param request - The request object. - * @param _response - The response object. Unused. - * @param next - The next middleware function. - * @param end - The end function. - * @param hooks - The hooks object. - * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin. - * @param hooks.getNetworkConfigurationByNetworkClientId - Function to retrieve a network configuration. - */ -export async function caipPermissionAdapterMiddleware( - request: JsonRpcRequest & { - networkClientId: NetworkClientId; - origin: string; - }, - _response: unknown, - next: () => Promise, - end: (error?: Error) => void, - hooks: { - getCaveatForOrigin: ( - ...args: unknown[] - ) => Caveat; - getNetworkConfigurationByNetworkClientId: ( - networkClientId: NetworkClientId, - ) => NetworkConfiguration; - }, -) { - const { networkClientId, method } = request; - - let caveat; - try { - caveat = hooks.getCaveatForOrigin( - Caip25EndowmentPermissionName, - Caip25CaveatType, - ); - } catch (err) { - // noop - } - if (!caveat?.value?.isMultichainOrigin) { - return next(); - } - - const { chainId } = - hooks.getNetworkConfigurationByNetworkClientId(networkClientId); - - const scope: InternalScopeString = `eip155:${hexToBigInt(chainId).toString( - 10, - )}`; - - const sessionScopes = getSessionScopes(caveat.value); - - if ( - !sessionScopes[scope]?.methods?.includes(method) && - !sessionScopes[KnownWalletScopeString.Eip155]?.methods?.includes(method) && - !sessionScopes.wallet?.methods?.includes(method) && - !Eip1193OnlyMethods.includes(method) - ) { - return end(providerErrors.unauthorized()); - } - - return next(); -} diff --git a/packages/multichain/src/index.ts b/packages/multichain/src/index.ts index 49b53a38e0d..60732796b47 100644 --- a/packages/multichain/src/index.ts +++ b/packages/multichain/src/index.ts @@ -11,7 +11,6 @@ export { getInternalScopesObject, getSessionScopes, } from './adapters/caip-permission-adapter-session-scopes'; -export { caipPermissionAdapterMiddleware } from './adapters/caip-permission-adapter-middleware'; export { walletGetSession } from './handlers/wallet-getSession'; export { walletInvokeMethod } from './handlers/wallet-invokeMethod'; From 96f372c9872dc5dfd51d7e752c66eddf4ad2e62b Mon Sep 17 00:00:00 2001 From: jiexi Date: Wed, 15 Jan 2025 10:59:34 -0800 Subject: [PATCH 132/146] Update packages/multichain/src/scope/authorization.test.ts Co-authored-by: Frederik Bolding --- packages/multichain/src/scope/authorization.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/scope/authorization.test.ts b/packages/multichain/src/scope/authorization.test.ts index 2514c630dce..885d71b0e07 100644 --- a/packages/multichain/src/scope/authorization.test.ts +++ b/packages/multichain/src/scope/authorization.test.ts @@ -149,7 +149,7 @@ describe('Scope Authorization', () => { ); }); - it('buckets the mayble supportable scopes', () => { + it('buckets the maybe supportable scopes', () => { const isChainIdSupportable = jest.fn(); bucketScopes( { From 8f02d61440ae8b3a110874ccfa327cc5ee2042f3 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 15 Jan 2025 11:23:47 -0800 Subject: [PATCH 133/146] Fix snapshot --- packages/multichain/src/index.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/multichain/src/index.test.ts b/packages/multichain/src/index.test.ts index aa2515458c6..8465d5a24fd 100644 --- a/packages/multichain/src/index.test.ts +++ b/packages/multichain/src/index.test.ts @@ -11,7 +11,6 @@ describe('@metamask/multichain', () => { "setPermittedEthChainIds", "getInternalScopesObject", "getSessionScopes", - "caipPermissionAdapterMiddleware", "walletGetSession", "walletInvokeMethod", "walletRevokeSession", From 20588efc71c848bba74884cc8a514f6cfcbc8f5b Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 15 Jan 2025 11:44:25 -0800 Subject: [PATCH 134/146] yarn lock --- yarn.lock | 2389 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 1374 insertions(+), 1015 deletions(-) diff --git a/yarn.lock b/yarn.lock index eb1c2729e12..6a417de7c06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,10 +193,10 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.25.9": - version: 7.26.3 - resolution: "@babel/compat-data@npm:7.26.3" - checksum: 10/0bf4e491680722aa0eac26f770f2fae059f92e2ac083900b241c90a2c10f0fc80e448b1feccc2b332687fab4c3e33e9f83dee9ef56badca1fb9f3f71266d9ebf +"@babel/compat-data@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/compat-data@npm:7.26.5" + checksum: 10/afe35751f27bda80390fa221d5e37be55b7fc42cec80de9896086e20394f2306936c4296fcb4d62b683e3b49ba2934661ea7e06196ca2dacdc2e779fbea4a1a9 languageName: node linkType: hard @@ -223,65 +223,65 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.3, @babel/generator@npm:^7.7.2": - version: 7.26.3 - resolution: "@babel/generator@npm:7.26.3" +"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.5, @babel/generator@npm:^7.7.2": + version: 7.26.5 + resolution: "@babel/generator@npm:7.26.5" dependencies: - "@babel/parser": "npm:^7.26.3" - "@babel/types": "npm:^7.26.3" + "@babel/parser": "npm:^7.26.5" + "@babel/types": "npm:^7.26.5" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10/c1d8710cc1c52af9d8d67f7d8ea775578aa500887b327d2a81e27494764a6ef99e438dd7e14cf7cd3153656492ee27a8362980dc438087c0ca39d4e75532c638 + checksum: 10/aa5f176155431d1fb541ca11a7deddec0fc021f20992ced17dc2f688a0a9584e4ff4280f92e8a39302627345cd325762f70f032764806c579c6fd69432542bcb languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" +"@babel/helper-annotate-as-pure@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10/a9017bfc1c4e9f2225b967fbf818004703de7cf29686468b54002ffe8d6b56e0808afa20d636819fcf3a34b89ba72f52c11bdf1d69f303928ee10d92752cad95 + "@babel/types": "npm:^7.25.9" + checksum: 10/41edda10df1ae106a9b4fe617bf7c6df77db992992afd46192534f5cff29f9e49a303231733782dd65c5f9409714a529f215325569f14282046e9d3b7a1ffb6c languageName: node linkType: hard "@babel/helper-compilation-targets@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-compilation-targets@npm:7.25.9" + version: 7.26.5 + resolution: "@babel/helper-compilation-targets@npm:7.26.5" dependencies: - "@babel/compat-data": "npm:^7.25.9" + "@babel/compat-data": "npm:^7.26.5" "@babel/helper-validator-option": "npm:^7.25.9" browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10/8053fbfc21e8297ab55c8e7f9f119e4809fa7e505268691e1bedc2cf5e7a5a7de8c60ad13da2515378621b7601c42e101d2d679904da395fa3806a1edef6b92e + checksum: 10/f3b5f0bfcd7b6adf03be1a494b269782531c6e415afab2b958c077d570371cf1bfe001c442508092c50ed3711475f244c05b8f04457d8dea9c34df2b741522bf languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.25.0": - version: 7.25.4 - resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4" +"@babel/helper-create-class-features-plugin@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-member-expression-to-functions": "npm:^7.24.8" - "@babel/helper-optimise-call-expression": "npm:^7.24.7" - "@babel/helper-replace-supers": "npm:^7.25.0" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.4" + "@babel/helper-annotate-as-pure": "npm:^7.25.9" + "@babel/helper-member-expression-to-functions": "npm:^7.25.9" + "@babel/helper-optimise-call-expression": "npm:^7.25.9" + "@babel/helper-replace-supers": "npm:^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10/47218da9fd964af30d41f0635d9e33eed7518e03aa8f10c3eb8a563bb2c14f52be3e3199db5912ae0e26058c23bb511c811e565c55ecec09427b04b867ed13c2 + checksum: 10/d1d47a7b5fd317c6cb1446b0e4f4892c19ddaa69ea0229f04ba8bea5f273fc8168441e7114ad36ff919f2d310f97310cec51adc79002e22039a7e1640ccaf248 languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" +"@babel/helper-member-expression-to-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" dependencies: - "@babel/traverse": "npm:^7.24.8" - "@babel/types": "npm:^7.24.8" - checksum: 10/ac878761cfd0a46c081cda0da75cc186f922cf16e8ecdd0c4fb6dca4330d9fe4871b41a9976224cf9669c9e7fe0421b5c27349f2e99c125fa0be871b327fa770 + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/ef8cc1c1e600b012b312315f843226545a1a89f25d2f474ce2503fd939ca3f8585180f291a3a13efc56cf13eddc1d41a3a040eae9a521838fd59a6d04cc82490 languageName: node linkType: hard @@ -295,7 +295,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.26.0": +"@babel/helper-module-transforms@npm:^7.26.0": version: 7.26.0 resolution: "@babel/helper-module-transforms@npm:7.26.0" dependencies: @@ -308,52 +308,42 @@ __metadata: languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" +"@babel/helper-optimise-call-expression@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10/da7a7f2d1bb1be4cffd5fa820bd605bc075c7dd014e0458f608bb6f34f450fe9412c8cea93e788227ab396e0e02c162d7b1db3fbcb755a6360e354c485d61df0 + "@babel/types": "npm:^7.25.9" + checksum: 10/f09d0ad60c0715b9a60c31841b3246b47d67650c512ce85bbe24a3124f1a4d66377df793af393273bc6e1015b0a9c799626c48e53747581c1582b99167cc65dc languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.24.8 - resolution: "@babel/helper-plugin-utils@npm:7.24.8" - checksum: 10/adbc9fc1142800a35a5eb0793296924ee8057fe35c61657774208670468a9fbfbb216f2d0bc46c680c5fefa785e5ff917cc1674b10bd75cdf9a6aa3444780630 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.26.5, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.26.5 + resolution: "@babel/helper-plugin-utils@npm:7.26.5" + checksum: 10/1cc0fd8514da3bb249bed6c27227696ab5e84289749d7258098701cffc0c599b7f61ec40dd332f8613030564b79899d9826813c96f966330bcfc7145a8377857 languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helper-replace-supers@npm:7.25.0" +"@babel/helper-replace-supers@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/helper-replace-supers@npm:7.26.5" dependencies: - "@babel/helper-member-expression-to-functions": "npm:^7.24.8" - "@babel/helper-optimise-call-expression": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.0" + "@babel/helper-member-expression-to-functions": "npm:^7.25.9" + "@babel/helper-optimise-call-expression": "npm:^7.25.9" + "@babel/traverse": "npm:^7.26.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10/97c6c17780cb9692132f7243f5a21fb6420104cb8ff8752dc03cfc9a1912a243994c0290c77ff096637ab6f2a7363b63811cfc68c2bad44e6b39460ac2f6a63f - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-simple-access@npm:7.24.7" - dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10/5083e190186028e48fc358a192e4b93ab320bd016103caffcfda81302a13300ccce46c9cd255ae520c25d2a6a9b47671f93e5fe5678954a2329dc0a685465c49 + checksum: 10/cfb911d001a8c3d2675077dbb74ee8d7d5533b22d74f8d775cefabf19c604f6cbc22cfeb94544fe8efa626710d920f04acb22923017e68f46f5fdb1cb08b32ad languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10/784a6fdd251a9a7e42ccd04aca087ecdab83eddc60fda76a2950e00eb239cc937d3c914266f0cc476298b52ac3f44ffd04c358e808bd17552a7e008d75494a77 + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/fdbb5248932198bc26daa6abf0d2ac42cab9c2dbb75b7e9f40d425c8f28f09620b886d40e7f9e4e08ffc7aaa2cefe6fc2c44be7c20e81f7526634702fb615bdc languageName: node linkType: hard @@ -371,7 +361,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.25.9": +"@babel/helper-validator-option@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-option@npm:7.25.9" checksum: 10/9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d @@ -388,14 +378,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.3": - version: 7.26.3 - resolution: "@babel/parser@npm:7.26.3" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/parser@npm:7.26.5" dependencies: - "@babel/types": "npm:^7.26.3" + "@babel/types": "npm:^7.26.5" bin: parser: ./bin/babel-parser.js - checksum: 10/e7e3814b2dc9ee3ed605d38223471fa7d3a84cbe9474d2b5fa7ac57dc1ddf75577b1fd3a93bf7db8f41f28869bda795cddd80223f980be23623b6434bf4c88a8 + checksum: 10/d92097066e3e26625a485149f54c27899e4d94d7ef2f76d8fc9de2019212e7951940a31c0003f26ccad22e664f89ff51e5d5fe80a11eafaaec2420655010533c languageName: node linkType: hard @@ -444,13 +434,13 @@ __metadata: linkType: hard "@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7" + version: 7.26.0 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/22fc50bd85a491bb8d22065f330a41f60d66f2f2d7a1deb73e80c8a4b5d7a42a092a03f8da18800650eca0fc14585167cc4e5c9fab351f0d390d1592347162ae + checksum: 10/c122aa577166c80ee67f75aebebeef4150a132c4d3109d25d7fc058bf802946f883e330f20b78c1d3e3a5ada631c8780c263d2d01b5dbaecc69efefeedd42916 languageName: node linkType: hard @@ -476,14 +466,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" +"@babel/plugin-syntax-jsx@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-syntax-jsx@npm:7.25.9" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/a93516ae5b34868ab892a95315027d4e5e38e8bd1cfca6158f2974b0901cbb32bbe64ea10ad5b25f919ddc40c6d8113c4823372909c9c9922170c12b0b1acecb + checksum: 10/bb609d1ffb50b58f0c1bac8810d0e46a4f6c922aa171c458f3a19d66ee545d36e782d3bffbbc1fed0dc65a558bdce1caf5279316583c0fff5a2c1658982a8563 languageName: node linkType: hard @@ -575,66 +565,65 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.25.4 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.4" +"@babel/plugin-syntax-typescript@npm:^7.25.9, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.25.9 + resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/0771b45a35fd536cd3b3a48e5eda0f53e2d4f4a0ca07377cc247efa39eaf6002ed1c478106aad2650e54aefaebcb4f34f3284c4ae9252695dbd944bf66addfb0 + checksum: 10/0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.23.3, @babel/plugin-transform-modules-commonjs@npm:^7.24.7": - version: 7.24.8 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" +"@babel/plugin-transform-modules-commonjs@npm:^7.23.3, @babel/plugin-transform-modules-commonjs@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.26.3" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.8" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-simple-access": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.26.0" + "@babel/helper-plugin-utils": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/18e5d229767c7b5b6ff0cbf1a8d2d555965b90201839d0ac2dc043b56857624ea344e59f733f028142a8c1d54923b82e2a0185694ef36f988d797bfbaf59819c + checksum: 10/f817f02fa04d13f1578f3026239b57f1003bebcf9f9b8d854714bed76a0e4986c79bd6d2e0ac14282c5d309454a8dab683c179709ca753b0152a69c69f3a78e3 languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.24.7": - version: 7.25.2 - resolution: "@babel/plugin-transform-typescript@npm:7.25.2" +"@babel/plugin-transform-typescript@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/plugin-transform-typescript@npm:7.26.5" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-create-class-features-plugin": "npm:^7.25.0" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" - "@babel/plugin-syntax-typescript": "npm:^7.24.7" + "@babel/helper-annotate-as-pure": "npm:^7.25.9" + "@babel/helper-create-class-features-plugin": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" + "@babel/plugin-syntax-typescript": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/50e017ffd131c08661daa22b6c759999bb7a6cdfbf683291ee4bcbea4ae839440b553d2f8896bcf049aca1d267b39f3b09e8336059e919e83149b5ad859671f6 + checksum: 10/28c315ed51cf6a23e14181ee8b265e6ae5bc474cd604e6dac5a4fa5aed114447972690a7d327d8f8e679b7fa18e52218fced0e2a039e4eb854c6016f00dff956 languageName: node linkType: hard "@babel/preset-typescript@npm:^7.23.3": - version: 7.24.7 - resolution: "@babel/preset-typescript@npm:7.24.7" + version: 7.26.0 + resolution: "@babel/preset-typescript@npm:7.26.0" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-validator-option": "npm:^7.24.7" - "@babel/plugin-syntax-jsx": "npm:^7.24.7" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7" - "@babel/plugin-transform-typescript": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-validator-option": "npm:^7.25.9" + "@babel/plugin-syntax-jsx": "npm:^7.25.9" + "@babel/plugin-transform-modules-commonjs": "npm:^7.25.9" + "@babel/plugin-transform-typescript": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/995e9783f8e474581e7533d6b10ec1fbea69528cc939ad8582b5937e13548e5215d25a8e2c845e7b351fdaa13139896b5e42ab3bde83918ea4e41773f10861ac + checksum: 10/81a60826160163a3daae017709f42147744757b725b50c9024ef3ee5a402ee45fd2e93eaecdaaa22c81be91f7940916249cfb7711366431cfcacc69c95878c03 languageName: node linkType: hard "@babel/runtime@npm:^7.23.9": - version: 7.25.4 - resolution: "@babel/runtime@npm:7.25.4" + version: 7.26.0 + resolution: "@babel/runtime@npm:7.26.0" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10/70d2a420c24a3289ea6c4addaf3a1c4186bc3d001c92445faa3cd7601d7d2fbdb32c63b3a26b9771e20ff2f511fa76b726bf256f823cdb95bc37b8eadbd02f70 + checksum: 10/9f4ea1c1d566c497c052d505587554e782e021e6ccd302c2ad7ae8291c8e16e3f19d4a7726fb64469e057779ea2081c28b7dbefec6d813a22f08a35712c0f699 languageName: node linkType: hard @@ -649,28 +638,28 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.7.2": - version: 7.26.4 - resolution: "@babel/traverse@npm:7.26.4" +"@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.5, @babel/traverse@npm:^7.7.2": + version: 7.26.5 + resolution: "@babel/traverse@npm:7.26.5" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.3" - "@babel/parser": "npm:^7.26.3" + "@babel/generator": "npm:^7.26.5" + "@babel/parser": "npm:^7.26.5" "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.3" + "@babel/types": "npm:^7.26.5" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10/30c81a80d66fc39842814bc2e847f4705d30f3859156f130d90a0334fe1d53aa81eed877320141a528ecbc36448acc0f14f544a7d410fa319d1c3ab63b50b58f + checksum: 10/b0131159450e3cd4208354cdea57e832e1a344fcc284b6ac84d1e13567a10501c4747bfd0ce637d2bd02277526b49372cfca71edd5c825cea74dcc9f52bb9225 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.3, @babel/types@npm:^7.3.3": - version: 7.26.3 - resolution: "@babel/types@npm:7.26.3" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.5, @babel/types@npm:^7.3.3": + version: 7.26.5 + resolution: "@babel/types@npm:7.26.5" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/c31d0549630a89abfa11410bf82a318b0c87aa846fbf5f9905e47ba5e2aa44f41cc746442f105d622c519e4dc532d35a8d8080460ff4692f9fc7485fbf3a00eb + checksum: 10/148f6bead7bc39371176ba681873c930087503a8bfd2b0dab5090de32752241806c95f4e87cee8b2976bb0277c6cbc150f16c333fc90269634b711d3711c0f18 languageName: node linkType: hard @@ -682,29 +671,29 @@ __metadata: linkType: hard "@contentful/content-source-maps@npm:^0.11.0": - version: 0.11.1 - resolution: "@contentful/content-source-maps@npm:0.11.1" + version: 0.11.7 + resolution: "@contentful/content-source-maps@npm:0.11.7" dependencies: "@vercel/stega": "npm:^0.1.2" json-pointer: "npm:^0.6.2" - checksum: 10/598e88349210aed21c9ee871250353ae15cb4130180ade9cf283261e192a80c72f8674c5533c490ad1358850e45578ed6ed4ac997b32c23b029ae4d096fa5646 + checksum: 10/7d228f73fc6be3aa2f341fcae7d15cdc60565d81dc9b0770a33f5d50aa729faeb6e33a19c2b8211932119857d06ab858e5e60da9778a5901f06940c7d2ecb78a languageName: node linkType: hard "@contentful/rich-text-html-renderer@npm:^16.5.2": - version: 16.6.9 - resolution: "@contentful/rich-text-html-renderer@npm:16.6.9" + version: 16.6.10 + resolution: "@contentful/rich-text-html-renderer@npm:16.6.10" dependencies: - "@contentful/rich-text-types": "npm:^16.8.4" + "@contentful/rich-text-types": "npm:^16.8.5" escape-html: "npm:^1.0.3" - checksum: 10/10bdcee4c01b89e5ab54ccab592bad7d3658fdd32ee58e2d5d18628a59ca47c7393c8dec41e96172b4c171f7fb4d2d1d6b9da9d6eeebbe5ed83fc3de8c4c0c89 + checksum: 10/fdf5121524355c96cd8a4628b2cc50a61b9b9d37da167dd983cc8fa24fa822427809d00064ebca9b85b8f40d92719f0b86f0e4ea4eaa8d078656ed56c51df6bb languageName: node linkType: hard -"@contentful/rich-text-types@npm:^16.0.2, @contentful/rich-text-types@npm:^16.8.4": - version: 16.8.4 - resolution: "@contentful/rich-text-types@npm:16.8.4" - checksum: 10/22e0a165545f32cc51d1e6231a9e7b617af98c452ecfb28ace9ba8a53b89bb2d940019ffae00ef2bc77c998630a66bfc88d01031e732afb11172f877064aa5b2 +"@contentful/rich-text-types@npm:^16.0.2, @contentful/rich-text-types@npm:^16.8.5": + version: 16.8.5 + resolution: "@contentful/rich-text-types@npm:16.8.5" + checksum: 10/7c1ec7088cc39bbd8f5edc14867ed3d59d06a55f2c92e6c62913aa2312056e920528e6ca6d59780b32c6fe2ab89c429b9f0bce9a52f456be7260f458527ccc3b languageName: node linkType: hard @@ -717,10 +706,10 @@ __metadata: languageName: node linkType: hard -"@endo/env-options@npm:^1.1.5": - version: 1.1.5 - resolution: "@endo/env-options@npm:1.1.5" - checksum: 10/ce4cb29ecf387f52f7d1c9e7e43b0a1064326587ebac62e7c239bf2df71aa4c3296d2a05cf169d1efcd8c1ddf73aeede8afd86e7b5c9387b80e8e0939d1af0f6 +"@endo/env-options@npm:^1.1.8": + version: 1.1.8 + resolution: "@endo/env-options@npm:1.1.8" + checksum: 10/f7e84346599dd2bcb6365c314e9a8129c5ebbb457476de72ed896ea461d616c0b7e0dfc7733e20c0abb8400212fb5eafdae993bcfd4cbfe92acbb5c881a6ad0d languageName: node linkType: hard @@ -764,12 +753,12 @@ __metadata: languageName: node linkType: hard -"@eslint/core@npm:^0.9.0": - version: 0.9.1 - resolution: "@eslint/core@npm:0.9.1" +"@eslint/core@npm:^0.10.0": + version: 0.10.0 + resolution: "@eslint/core@npm:0.10.0" dependencies: "@types/json-schema": "npm:^7.0.15" - checksum: 10/f2263f8f94fdf84fc34573e027de98f1fce6287120513ae672ddf0652c75b9fa77c314d565628fc58e0a6f959766acc34c8191f9b94f1757b910408ffa04adde + checksum: 10/de41d7fa5dc468b70fb15c72829096939fc0217c41b8519af4620bc1089cb42539a15325c4c3ee3832facac1836c8c944c4a0c4d0cc8b33ffd8e95962278ae14 languageName: node linkType: hard @@ -790,10 +779,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.17.0, @eslint/js@npm:^9.11.0": - version: 9.17.0 - resolution: "@eslint/js@npm:9.17.0" - checksum: 10/1a89e62f5c50e75d44565b7f3b91701455a999132c991e10bac59c118fbb54bdd54be22b9bda1ac730f78a2e64604403d65ce5dd7726d80b2632982cfc3d84ac +"@eslint/js@npm:9.18.0, @eslint/js@npm:^9.11.0": + version: 9.18.0 + resolution: "@eslint/js@npm:9.18.0" + checksum: 10/364a7d030dad9dbda1458d8dbcea0199fe7d48bcfefe4b49389df6c45cdc5a2449f70e5d8a794e46ed9fb34af3fe5a3f53e30020d306b6ee791e2a1b2b9fa25f languageName: node linkType: hard @@ -804,12 +793,13 @@ __metadata: languageName: node linkType: hard -"@eslint/plugin-kit@npm:^0.2.3": - version: 0.2.4 - resolution: "@eslint/plugin-kit@npm:0.2.4" +"@eslint/plugin-kit@npm:^0.2.5": + version: 0.2.5 + resolution: "@eslint/plugin-kit@npm:0.2.5" dependencies: + "@eslint/core": "npm:^0.10.0" levn: "npm:^0.4.1" - checksum: 10/e34d02ea1dccd716e51369620263a4b2167aff3c0510ed776e21336cc3ad7158087449a76931baf07cdc33810cb6919db375f2e9f409435d2c6e0dd5f4786b25 + checksum: 10/82d0142bc7054587bde4f75c2c517f477df7c320e4bdb47a4d5f766899a313ce65e9ce5d59428178d0be473a95292065053f69637042546b811ad89079781cbc languageName: node linkType: hard @@ -1145,25 +1135,18 @@ __metadata: languageName: node linkType: hard -"@fastify/busboy@npm:^2.0.0": - version: 2.1.1 - resolution: "@fastify/busboy@npm:2.1.1" - checksum: 10/2bb8a7eca8289ed14c9eb15239bc1019797454624e769b39a0b90ed204d032403adc0f8ed0d2aef8a18c772205fa7808cf5a1b91f21c7bfc7b6032150b1062c5 - languageName: node - linkType: hard - -"@firebase/analytics-compat@npm:0.2.13": - version: 0.2.13 - resolution: "@firebase/analytics-compat@npm:0.2.13" +"@firebase/analytics-compat@npm:0.2.14": + version: 0.2.14 + resolution: "@firebase/analytics-compat@npm:0.2.14" dependencies: - "@firebase/analytics": "npm:0.10.7" + "@firebase/analytics": "npm:0.10.8" "@firebase/analytics-types": "npm:0.8.2" - "@firebase/component": "npm:0.6.8" - "@firebase/util": "npm:1.9.7" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/37af40ac540c68593a118e75c0fc2031459633b46d3fd32f97290fd8c3865fe425cc85feac2243c461924da698e27f4a5c174898e847027b5afd347274080c9c + checksum: 10/0e368159d24223076b488b27308c11e5ef50456aff49fc58e1f66616228021c61e60c3299f63ce52ddc2f7099d803e9048bc28cd952cf5c302917002c03c85ee languageName: node linkType: hard @@ -1174,34 +1157,34 @@ __metadata: languageName: node linkType: hard -"@firebase/analytics@npm:0.10.7": - version: 0.10.7 - resolution: "@firebase/analytics@npm:0.10.7" +"@firebase/analytics@npm:0.10.8": + version: 0.10.8 + resolution: "@firebase/analytics@npm:0.10.8" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/installations": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/610c67d4ebbd671ace4d0baf2fa7733e1fa97a2f900cb6337b054528a7c98110d861030b2f3c95553ed81253a9cd152edf2b9dc9388a8bec679050bf46674cfe + checksum: 10/152ddaf68146f02baa7060d34426c25ec13890a53942ffa2db09faa148bef35f59ee9810e6fb8f561fb3d115b71d1fb9fb111d2a0f0199aa510220782557c765 languageName: node linkType: hard -"@firebase/app-check-compat@npm:0.3.14": - version: 0.3.14 - resolution: "@firebase/app-check-compat@npm:0.3.14" +"@firebase/app-check-compat@npm:0.3.15": + version: 0.3.15 + resolution: "@firebase/app-check-compat@npm:0.3.15" dependencies: - "@firebase/app-check": "npm:0.8.7" + "@firebase/app-check": "npm:0.8.8" "@firebase/app-check-types": "npm:0.5.2" - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/8d4c835fa95474d556b36ec73f571f3e967cbe590cc76f9964eb9d50905becadf195c5e3cd628fc278efb162529a86a0b5433b72d5d232249168865ab8564392 + checksum: 10/ae541d324d5f91dbb7b479855d3380c4fe73e365013b80973a54620405093e6fd2f8e418549155b3a527530472a19b6edf6df1481a708f823eba42e376105b28 languageName: node linkType: hard @@ -1219,30 +1202,30 @@ __metadata: languageName: node linkType: hard -"@firebase/app-check@npm:0.8.7": - version: 0.8.7 - resolution: "@firebase/app-check@npm:0.8.7" +"@firebase/app-check@npm:0.8.8": + version: 0.8.8 + resolution: "@firebase/app-check@npm:0.8.8" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/3f09160bccd99006e33d7bc342dc6c242094be7ffccc6ff0259207006f93f645badb5c1c1743c8a1540d0dab6536a5019eff0ba231b37488ead1209b853287ac + checksum: 10/a3676f2143c8e438d7e8ac11bb163af30880f6ce6acc5cc54cfcc214b8efd5dabce14c040626f8a64a3967db144b99834f1108c2076a0eae8a6baf864b5a3d77 languageName: node linkType: hard -"@firebase/app-compat@npm:0.2.39": - version: 0.2.39 - resolution: "@firebase/app-compat@npm:0.2.39" +"@firebase/app-compat@npm:0.2.43": + version: 0.2.43 + resolution: "@firebase/app-compat@npm:0.2.43" dependencies: - "@firebase/app": "npm:0.10.9" - "@firebase/component": "npm:0.6.8" + "@firebase/app": "npm:0.10.13" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - checksum: 10/266a35f349417d8f5ecc69b4d877b0a41e4ef78ddd927fa8f90eb15ea3d709bed7d504b6be49407e2a1e14ad392933be6aff5eb67c2127ab68a00ddb7c26f806 + checksum: 10/e27340dbc9804ffd0d469cc1fa919cd61b6e04fe96599d14414aa06c3dcbe75b23c324f0bedfff4dbd5d9b829b8dde5a2e8b5464f1f686d66f9c00971d9d4c56 languageName: node linkType: hard @@ -1253,32 +1236,32 @@ __metadata: languageName: node linkType: hard -"@firebase/app@npm:0.10.9": - version: 0.10.9 - resolution: "@firebase/app@npm:0.10.9" +"@firebase/app@npm:0.10.13": + version: 0.10.13 + resolution: "@firebase/app@npm:0.10.13" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" idb: "npm:7.1.1" tslib: "npm:^2.1.0" - checksum: 10/faf344390ce2a857171ca347ca6b81b867b6d4acd87232698c4a93678100c82308796cf906cecad287dadcc83b0a645a22678292b3fb3a97c94cc3ee44c88609 + checksum: 10/54ec64b3a992c2f30c800fb5638bf586e7e7f351899887c701d5f946ad8ca445d8c1d3024007b7939a7e6ae29a51d90567552a863323594dc6fca22f1e811e0b languageName: node linkType: hard -"@firebase/auth-compat@npm:0.5.12": - version: 0.5.12 - resolution: "@firebase/auth-compat@npm:0.5.12" +"@firebase/auth-compat@npm:0.5.14": + version: 0.5.14 + resolution: "@firebase/auth-compat@npm:0.5.14" dependencies: - "@firebase/auth": "npm:1.7.7" + "@firebase/auth": "npm:1.7.9" "@firebase/auth-types": "npm:0.12.2" - "@firebase/component": "npm:0.6.8" - "@firebase/util": "npm:1.9.7" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - undici: "npm:5.28.4" + undici: "npm:6.19.7" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/1eeeec3ce7983dbadd1e95cf75e7665486d68eb60b0bc56642412120bdb05d2a389294343532b3cff2114ab8b782c00620ddecf5c194944bfcaead016075a568 + checksum: 10/85d5259e7b04b14b5d02dc1fb19b015d742c594c14138f33f13146ed9f6caa7ed9d19d65bb99aaca57e70ffd2a491e520d8638eadefbd00f839d37ef972cbbda languageName: node linkType: hard @@ -1299,86 +1282,101 @@ __metadata: languageName: node linkType: hard -"@firebase/auth@npm:1.7.7": - version: 1.7.7 - resolution: "@firebase/auth@npm:1.7.7" +"@firebase/auth@npm:1.7.9": + version: 1.7.9 + resolution: "@firebase/auth@npm:1.7.9" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - undici: "npm:5.28.4" + undici: "npm:6.19.7" peerDependencies: "@firebase/app": 0.x "@react-native-async-storage/async-storage": ^1.18.1 peerDependenciesMeta: "@react-native-async-storage/async-storage": optional: true - checksum: 10/fe329cdb9cd827cf0c3dd6cba6090496b79bcc09b0e53e685026dc9a1c723310387d4e3655d300ed4789608c7d0fcacbb666c19c4c2be7f416dcc47fb91df0cd + checksum: 10/010013ec339c9ef7b4d9278c6cacfd8e2eb3282f27a3e4e89c42a5968955976a26277421f34fda3e9400409a22a61f632bcc03e713b3f39d71e4777bc003165d languageName: node linkType: hard -"@firebase/component@npm:0.6.8": - version: 0.6.8 - resolution: "@firebase/component@npm:0.6.8" +"@firebase/component@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/component@npm:0.6.9" dependencies: - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - checksum: 10/0df2a61a9d3a32981a82889b4f23923c9adc468e89cadec5984b52d2422bb2b184c1219ed78dc7ec0b7f973ac0b7c2e8f486dee4a32a6741c0627648960e4314 + checksum: 10/76c865d640e4b24a0e50876ecdc0e1199df38af562131a937b5a4bac924d61b6933339afb7906881dca509f38f3b0c511cd6b5008e061424c61b20876de9531e languageName: node linkType: hard -"@firebase/database-compat@npm:1.0.7": - version: 1.0.7 - resolution: "@firebase/database-compat@npm:1.0.7" +"@firebase/data-connect@npm:0.1.0": + version: 0.1.0 + resolution: "@firebase/data-connect@npm:0.1.0" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/database": "npm:1.0.7" - "@firebase/database-types": "npm:1.0.4" + "@firebase/auth-interop-types": "npm:0.2.3" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - checksum: 10/87d6185b65d58784e0c645a8be232f034d7e3bdfbe030b7d88b5597f7d18dc9329a6c6b0eab84f887ab87ef34caf171afc5b97bbd917fa8682015286cb9fcad4 + peerDependencies: + "@firebase/app": 0.x + checksum: 10/20dac7c4755a0dde17abea0c99b41e96c9f7eea6ea39c36fd85f3f5554991b718a25b4bc1f92850208ec1f0e3b1ee584b1cf1913c4ad6c41643655682c06a2b0 languageName: node linkType: hard -"@firebase/database-types@npm:1.0.4": - version: 1.0.4 - resolution: "@firebase/database-types@npm:1.0.4" +"@firebase/database-compat@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database-compat@npm:1.0.8" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/database": "npm:1.0.8" + "@firebase/database-types": "npm:1.0.5" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + checksum: 10/28389efcc87da77b822cb27c31707824fe98e7b0a3bf9cbf2b0c0fccd9edd72e2681a9467b76b120281464dbfc814852ebca63d99a385a9cb68fb55c7b334105 + languageName: node + linkType: hard + +"@firebase/database-types@npm:1.0.5": + version: 1.0.5 + resolution: "@firebase/database-types@npm:1.0.5" dependencies: "@firebase/app-types": "npm:0.9.2" - "@firebase/util": "npm:1.9.7" - checksum: 10/d76125998d322d1fa31a6bf028e21ba03eafb26d7ae3b408ea8f84f52caf1dea716a236a21c64deb857c5eb091ea53cf148b9a2b99f4e97efc5b7c8cabae9acd + "@firebase/util": "npm:1.10.0" + checksum: 10/bdf667da0369dce8623987fc01cad8db09cfe1895130f69ab581d34a0ee043ca6113c32457629147ae1441a934d985ede9d7cbe104ac346de6d0c21629903a8b languageName: node linkType: hard -"@firebase/database@npm:1.0.7": - version: 1.0.7 - resolution: "@firebase/database@npm:1.0.7" +"@firebase/database@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database@npm:1.0.8" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" "@firebase/auth-interop-types": "npm:0.2.3" - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" faye-websocket: "npm:0.11.4" tslib: "npm:^2.1.0" - checksum: 10/d299c07ac647efb09b644ff91c2aa1d49622c16adc40f75506563aeb8de73f79b17949a13db8089337497e570cebf0df69e8404e934d44a49bb703d05375c245 + checksum: 10/adb199a6ad7866b418e8b319cc505e108bfc8200b5406f21857706df0849d4e5982a1b0e44e07001821edebef73c4dfffc7f96fb77a2cff10bb9ac26f17d40c3 languageName: node linkType: hard -"@firebase/firestore-compat@npm:0.3.35": - version: 0.3.35 - resolution: "@firebase/firestore-compat@npm:0.3.35" +"@firebase/firestore-compat@npm:0.3.38": + version: 0.3.38 + resolution: "@firebase/firestore-compat@npm:0.3.38" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/firestore": "npm:4.7.0" + "@firebase/component": "npm:0.6.9" + "@firebase/firestore": "npm:4.7.3" "@firebase/firestore-types": "npm:3.0.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/e3d4cb5cbf555e840eef862cace318d5dc829546c2c7e29d8cabd5ff5d0eb7c756405c4985490c0e1cd524b3dd1ed4e19d4d4a06230e5b6126adac0571010d99 + checksum: 10/de9e92b5ac612ea73322407b65b1d90067f7138d2159bcfd2400535d09968ea8c8b44956282172129eca78bf951f74a6991394b2634913458927570bb4fa8cd8 languageName: node linkType: hard @@ -1392,36 +1390,36 @@ __metadata: languageName: node linkType: hard -"@firebase/firestore@npm:4.7.0": - version: 4.7.0 - resolution: "@firebase/firestore@npm:4.7.0" +"@firebase/firestore@npm:4.7.3": + version: 4.7.3 + resolution: "@firebase/firestore@npm:4.7.3" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" "@firebase/webchannel-wrapper": "npm:1.0.1" "@grpc/grpc-js": "npm:~1.9.0" "@grpc/proto-loader": "npm:^0.7.8" tslib: "npm:^2.1.0" - undici: "npm:5.28.4" + undici: "npm:6.19.7" peerDependencies: "@firebase/app": 0.x - checksum: 10/b3cb3a62bd3cc5b7ade8689d396d0b0a49821d8709caf787078bbc9306e5d4ddbcb20afbda5138b09934e5fc30ce3561e53419776e7ca454a5025fd195343b12 + checksum: 10/f46a6e3c03eadfa970d8ecc17627d0d696931a19092fcf5be4b2056a209da3691be0bd040a11d333d26c15fd14329ce0fb5dfc32bf2cfa530a4d035b45ef4edf languageName: node linkType: hard -"@firebase/functions-compat@npm:0.3.12": - version: 0.3.12 - resolution: "@firebase/functions-compat@npm:0.3.12" +"@firebase/functions-compat@npm:0.3.14": + version: 0.3.14 + resolution: "@firebase/functions-compat@npm:0.3.14" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/functions": "npm:0.11.6" + "@firebase/component": "npm:0.6.9" + "@firebase/functions": "npm:0.11.8" "@firebase/functions-types": "npm:0.6.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/d9803c909e848dc381c892d36885a9519b5b025a46afb2c096bf099e840c5c0afc2290b5660a9d763cf6a8bf0ad6f303f85d3011abfc02d75348452bfe3200c8 + checksum: 10/a8d6cbcdc646d78adecfcdc1f8fa14a5d9af2394dd69cac00c6826106b923e01d246c67fb7e09025ca7cfb876f8d5df97240cc056c64ccee8899ca5f17178a6c languageName: node linkType: hard @@ -1432,35 +1430,35 @@ __metadata: languageName: node linkType: hard -"@firebase/functions@npm:0.11.6": - version: 0.11.6 - resolution: "@firebase/functions@npm:0.11.6" +"@firebase/functions@npm:0.11.8": + version: 0.11.8 + resolution: "@firebase/functions@npm:0.11.8" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" "@firebase/auth-interop-types": "npm:0.2.3" - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/messaging-interop-types": "npm:0.2.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - undici: "npm:5.28.4" + undici: "npm:6.19.7" peerDependencies: "@firebase/app": 0.x - checksum: 10/c1ac2887dd986c8abc408db1da26531f5f9d252f2cd4ee36352239ed0a0fc11902dd1f85db9ec21818028fd737c5a09461c01c0701c85f9ea96b9dc8dfc69f03 + checksum: 10/44f3e42df189f3f3cb3c366b38e93a0ffdfaa1a7b3f6dba624bcd9a7cda3d3271df66f2769b7cbe7e1e5ff01bf6ab3bef6c1e1e15c6646e34514d1e2ebb60555 languageName: node linkType: hard -"@firebase/installations-compat@npm:0.2.8": - version: 0.2.8 - resolution: "@firebase/installations-compat@npm:0.2.8" +"@firebase/installations-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/installations-compat@npm:0.2.9" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/installations": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" "@firebase/installations-types": "npm:0.5.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/b0eece054763ac6d229b2fca7ead9cbdd10e6c8429be9f03d95e8ed4a488fcf1cbc3a136f49800b07f2b82fb0f5ff1fecb41bee923aa045314ed854bada256d8 + checksum: 10/919e1a4f4b63f5fe757a3c9cefb4a36cbab92deb4a6e15f249c94d6e80d1c6d37e5e384a460af8c17fc88e3091594bf43d036c88b704516c279b5ab8401977e1 languageName: node linkType: hard @@ -1473,17 +1471,17 @@ __metadata: languageName: node linkType: hard -"@firebase/installations@npm:0.6.8": - version: 0.6.8 - resolution: "@firebase/installations@npm:0.6.8" +"@firebase/installations@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/installations@npm:0.6.9" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/util": "npm:1.9.7" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" idb: "npm:7.1.1" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/84cdf30d393fad859f035b276c0ef372cd94907fe042498cdd7c24a719d786866a2f976834b90a49c543e37ae317edd669676830ba7cd83f3a3d34b6f2c0f1ee + checksum: 10/349c8b7e877b002fb29f274f4d239fbca4c2c266ccb66ecfb5f1762f973a7fe1be99cc3346184d1230e6e35feb2b6f9e8b7169479fa0018b53e4a83837848619 languageName: node linkType: hard @@ -1496,17 +1494,17 @@ __metadata: languageName: node linkType: hard -"@firebase/messaging-compat@npm:0.2.10": - version: 0.2.10 - resolution: "@firebase/messaging-compat@npm:0.2.10" +"@firebase/messaging-compat@npm:0.2.12": + version: 0.2.12 + resolution: "@firebase/messaging-compat@npm:0.2.12" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/messaging": "npm:0.12.10" - "@firebase/util": "npm:1.9.7" + "@firebase/component": "npm:0.6.9" + "@firebase/messaging": "npm:0.12.12" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/3565546cc935f553c0331dc86e593cd39e09c198c549e801dfb9d4ee53152fcc3bab277355bf1a82a063506b8462038dbd3d2122178b9c1edd39c08a0503244d + checksum: 10/0437ba6b24327d9eb02dc87ba61146fbb9720491ad671dc554438ac87e162d5fb154c704400d55c87ce01dd5aeedada9d0367fd114d840ead0d07802475eaa60 languageName: node linkType: hard @@ -1517,35 +1515,35 @@ __metadata: languageName: node linkType: hard -"@firebase/messaging@npm:0.12.10": - version: 0.12.10 - resolution: "@firebase/messaging@npm:0.12.10" +"@firebase/messaging@npm:0.12.12": + version: 0.12.12 + resolution: "@firebase/messaging@npm:0.12.12" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/installations": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" "@firebase/messaging-interop-types": "npm:0.2.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" idb: "npm:7.1.1" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/c883b465da2cdee0e08f37119bcb4eb1152bec482fe87136f4dbc6fc9ffbbba1f7c25fff70948844633949ab77bc38d81afd31e7227bf398863cccb878be3095 + checksum: 10/a00125489085782faf189ad42f75bed108c6632b9d198d114e0a8ce28d89f9455b4f78ff8f7d24d4a86ad13e1e14e0f17fa2ff3605c6dd0c8ff1b65fef23ce3d languageName: node linkType: hard -"@firebase/performance-compat@npm:0.2.8": - version: 0.2.8 - resolution: "@firebase/performance-compat@npm:0.2.8" +"@firebase/performance-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/performance-compat@npm:0.2.9" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/performance": "npm:0.6.8" + "@firebase/performance": "npm:0.6.9" "@firebase/performance-types": "npm:0.2.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/354a31f31c0d07df10a2b33f4ef2b34ba931cb51738c533c5af9e85c1645d9421f2262ec72eb54a3821f1df52644254f92b866d836c528d6a8ff91b399a2aad4 + checksum: 10/bc4e8b0208c9bc603518e1388713ec80658ee109c6af80d429479447ccb85e8e831269383233c379ed66bf37469d13f5c234074d0c0c9e7e69e909be5fdeca4f languageName: node linkType: hard @@ -1556,34 +1554,34 @@ __metadata: languageName: node linkType: hard -"@firebase/performance@npm:0.6.8": - version: 0.6.8 - resolution: "@firebase/performance@npm:0.6.8" +"@firebase/performance@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/performance@npm:0.6.9" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/installations": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/5c989d154daea84f009f221245231bf5050cf0d96688bf1b20add98429088c815cc6e76e91180394c9d7fe5759094bbe4261c13604ff349c67e3d7113959b146 + checksum: 10/d682d0b1e342ed3eda1a5ddab39c8ddac33afc9edb2c7335a2f9a28eb8c268b975bbf450a3bad5443138edebaf2aa731dca0b774bcf3211a6dc215b35d86d849 languageName: node linkType: hard -"@firebase/remote-config-compat@npm:0.2.8": - version: 0.2.8 - resolution: "@firebase/remote-config-compat@npm:0.2.8" +"@firebase/remote-config-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/remote-config-compat@npm:0.2.9" dependencies: - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/remote-config": "npm:0.4.8" + "@firebase/remote-config": "npm:0.4.9" "@firebase/remote-config-types": "npm:0.3.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/342b27720635c7f68ce8953cd22a5badfc628c3fb9414b32d40a2eaacb2feb2068079eac15c3c811f4327a06d01aa71631a6f2cfe8b80460f1910cfd37126342 + checksum: 10/a6db7509512d8d22b7ddf1127c741715e379e04e5b3246372bb0302d7c84afb421a94550adebecddcce5def115d61729a9580940dce6e65f8d77f9af30f69fe1 languageName: node linkType: hard @@ -1594,33 +1592,33 @@ __metadata: languageName: node linkType: hard -"@firebase/remote-config@npm:0.4.8": - version: 0.4.8 - resolution: "@firebase/remote-config@npm:0.4.8" +"@firebase/remote-config@npm:0.4.9": + version: 0.4.9 + resolution: "@firebase/remote-config@npm:0.4.9" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/installations": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/58f934b8cdc8582f260a8caf5b903d484d74aecba420221bf57e5df28f8ba7d3f9ca1ab58946c90ab2c29659bbfdad679fc59247468068063a5329d92cd27613 + checksum: 10/f14189f38c8cf75db16bf8b85dd004486b1dd8242f62d697c716fa85cd32928aed549ccea8c632a528870a424fc7f04f1132a14b3b099276cd7696c78e644b28 languageName: node linkType: hard -"@firebase/storage-compat@npm:0.3.10": - version: 0.3.10 - resolution: "@firebase/storage-compat@npm:0.3.10" +"@firebase/storage-compat@npm:0.3.12": + version: 0.3.12 + resolution: "@firebase/storage-compat@npm:0.3.12" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/storage": "npm:0.13.0" + "@firebase/component": "npm:0.6.9" + "@firebase/storage": "npm:0.13.2" "@firebase/storage-types": "npm:0.8.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/63486c25c9b241ad5a55d9ab0a448ee9fc6a53b39733709ea56bce26e32cbdd1e8d4a22601a233ee18734ba1111a7ee52ca0196c281d0f4a88061a555306efb1 + checksum: 10/4eea49a57f1d7537da697e5ff8b4e035ff1af69e416e7eab14485753c39c25eaa5a71bd2bafba0985ac6a7ce803f98f2f2f83c613c78c8f74bce286e3259b8ec languageName: node linkType: hard @@ -1634,42 +1632,42 @@ __metadata: languageName: node linkType: hard -"@firebase/storage@npm:0.13.0": - version: 0.13.0 - resolution: "@firebase/storage@npm:0.13.0" +"@firebase/storage@npm:0.13.2": + version: 0.13.2 + resolution: "@firebase/storage@npm:0.13.2" dependencies: - "@firebase/component": "npm:0.6.8" - "@firebase/util": "npm:1.9.7" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" - undici: "npm:5.28.4" + undici: "npm:6.19.7" peerDependencies: "@firebase/app": 0.x - checksum: 10/b33708f14ccb4aa7755a1e4dea3ce483aec0bd077bb9db8df4238f4c96f80e39ef687940ece39c3fa7dcceb0f6e5f3a22874f19dc8d05246226d4c1637508158 + checksum: 10/d887f80cf95ef5daa80ffb2e6d564d25abb8a3e84099bee9730c95082597a12028bbf73bfe66fca2df3cdf04eaadea8e9d74ec0a826f946bc8f002293a9983ea languageName: node linkType: hard -"@firebase/util@npm:1.9.7": - version: 1.9.7 - resolution: "@firebase/util@npm:1.9.7" +"@firebase/util@npm:1.10.0": + version: 1.10.0 + resolution: "@firebase/util@npm:1.10.0" dependencies: tslib: "npm:^2.1.0" - checksum: 10/c31290f45794af68a3ab571db1c0e3cb4d15443adfdc50107b835274b4ad525f839ee79a0da2898dd8b31e64ff811c126d338b0bab117be59c0a065ce984a89a + checksum: 10/eb161f1c6294ff097f3c40236820e9e6e29cd6582e5e1254148157143272493580535ee2cb9e7c6055d3909b3ef39d8b64086895b071c665827acb66742b63eb languageName: node linkType: hard -"@firebase/vertexai-preview@npm:0.0.3": - version: 0.0.3 - resolution: "@firebase/vertexai-preview@npm:0.0.3" +"@firebase/vertexai-preview@npm:0.0.4": + version: 0.0.4 + resolution: "@firebase/vertexai-preview@npm:0.0.4" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" - "@firebase/component": "npm:0.6.8" + "@firebase/component": "npm:0.6.9" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.9.7" + "@firebase/util": "npm:1.10.0" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x "@firebase/app-types": 0.x - checksum: 10/490ea78f153b764e117989cb0ee9abeb0f456c6daefc58aa949147b1404a2d90d49c84a04556f8d84a729692ca99ed670b9dd9b37169b93ac01dc8d9242dac13 + checksum: 10/8ec48d81f48aebdcc63b65d802c67bf36880f256e5c2f5f3b152dc91c8c0e924053fba2fac5218716612f8ee720b25d0822337a214f16f5b7e51ce0247dfc4e5 languageName: node linkType: hard @@ -1794,6 +1792,15 @@ __metadata: languageName: node linkType: hard +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10/4412e9e6713c89c1e66d80bb0bb5a2a93192f10477623a27d08f228ba0316bb880affabc5bfe7f838f58a34d26c2c190da726e576cdfc18c49a72e89adabdcf5 + languageName: node + linkType: hard + "@istanbuljs/load-nyc-config@npm:^1.0.0": version: 1.1.0 resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" @@ -2084,13 +2091,13 @@ __metadata: linkType: hard "@jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.5 - resolution: "@jridgewell/gen-mapping@npm:0.3.5" + version: 0.3.8 + resolution: "@jridgewell/gen-mapping@npm:0.3.8" dependencies: "@jridgewell/set-array": "npm:^1.2.1" "@jridgewell/sourcemap-codec": "npm:^1.4.10" "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/81587b3c4dd8e6c60252122937cea0c637486311f4ed208b52b62aae2e7a87598f63ec330e6cd0984af494bfb16d3f0d60d3b21d7e5b4aedd2602ff3fe9d32e2 + checksum: 10/9d3a56ab3612ab9b85d38b2a93b87f3324f11c5130859957f6500e4ac8ce35f299d5ccc3ecd1ae87597601ecf83cee29e9afd04c18777c24011073992ff946df languageName: node linkType: hard @@ -2242,31 +2249,32 @@ __metadata: languageName: node linkType: hard -"@lavamoat/aa@npm:^4.3.0": - version: 4.3.0 - resolution: "@lavamoat/aa@npm:4.3.0" +"@lavamoat/aa@npm:^4.3.1": + version: 4.3.1 + resolution: "@lavamoat/aa@npm:4.3.1" dependencies: resolve: "npm:1.22.8" bin: lavamoat-ls: src/cli.js - checksum: 10/c6c24ea88194ad06a83cc2a9e0b6918ee41ab40abcc5c889e1a33f214e48eb160dd0c4cea7b0e299f86d472810ef80e7caf0b2600499222b108690516d9f8123 + checksum: 10/664692b22c6fcf44a47259ec3b48873c0064872a5a285c7ee4ddc0f99217d5a6653236304cc393f03970f0810694ab44d1f02ce4c980ce86cc24b0e27e9c622f languageName: node linkType: hard "@lavamoat/allow-scripts@npm:^3.0.4": - version: 3.2.0 - resolution: "@lavamoat/allow-scripts@npm:3.2.0" + version: 3.3.1 + resolution: "@lavamoat/allow-scripts@npm:3.3.1" dependencies: - "@lavamoat/aa": "npm:^4.3.0" + "@lavamoat/aa": "npm:^4.3.1" "@npmcli/run-script": "npm:8.1.0" bin-links: "npm:4.0.4" npm-normalize-package-bin: "npm:3.0.1" + type-fest: "npm:4.30.0" yargs: "npm:17.7.2" peerDependencies: "@lavamoat/preinstall-always-fail": "*" bin: allow-scripts: src/cli.js - checksum: 10/21afb11ce25c0b2c9763bfb8f1127bb89f304ed83f64e00955c4d3007216a0ee553b777359e9ded874c61b3d7fa8d19ff8a35881cd3816985adab4d6b58bcb07 + checksum: 10/78bb7502136cee509592e66a1824a3e049a392e79740d99f528774743934d28e2099d3e80beded9a6623ce8842250d6207ebeea694d08c87e4fd8e2899eb0d7a languageName: node linkType: hard @@ -2379,13 +2387,13 @@ __metadata: linkType: soft "@metamask/api-specs@npm:^0.10.12": - version: 0.10.12 - resolution: "@metamask/api-specs@npm:0.10.12" - checksum: 10/e592f27f350994688d3d54a8a8db16de033011ef665efe3283a77431914d8d69d1c3312fad33e4245b4984e1223b04c98da3d0a68c7f9577cf8290ba441c52ee + version: 0.10.13 + resolution: "@metamask/api-specs@npm:0.10.13" + checksum: 10/c3a4d61a4fa5a610ee8c7bec68852d8a301e9003493ae3a37e475329cf1d37036746f3d9417026e13670eafc848895ff6274fe12472d34338f344d2f80c32d8d languageName: node linkType: hard -"@metamask/approval-controller@npm:^7.1.1, @metamask/approval-controller@npm:^7.1.2, @metamask/approval-controller@workspace:packages/approval-controller": +"@metamask/approval-controller@npm:^7.1.2, @metamask/approval-controller@workspace:packages/approval-controller": version: 0.0.0-use.local resolution: "@metamask/approval-controller@workspace:packages/approval-controller" dependencies: @@ -2505,7 +2513,7 @@ __metadata: languageName: node linkType: hard -"@metamask/base-controller@npm:^7.0.2, @metamask/base-controller@npm:^7.1.1, @metamask/base-controller@workspace:packages/base-controller": +"@metamask/base-controller@npm:^7.0.3, @metamask/base-controller@npm:^7.1.1, @metamask/base-controller@workspace:packages/base-controller": version: 0.0.0-use.local resolution: "@metamask/base-controller@workspace:packages/base-controller" dependencies: @@ -2775,16 +2783,16 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-block-tracker@npm:^11.0.3": - version: 11.0.3 - resolution: "@metamask/eth-block-tracker@npm:11.0.3" +"@metamask/eth-block-tracker@npm:^11.0.3, @metamask/eth-block-tracker@npm:^11.0.4": + version: 11.0.4 + resolution: "@metamask/eth-block-tracker@npm:11.0.4" dependencies: "@metamask/eth-json-rpc-provider": "npm:^4.1.5" "@metamask/safe-event-emitter": "npm:^3.1.1" - "@metamask/utils": "npm:^9.1.0" + "@metamask/utils": "npm:^11.0.1" json-rpc-random-id: "npm:^1.0.1" pify: "npm:^5.0.0" - checksum: 10/c73a570f889c613ab309643c84a4aed1a4eeed5c101434da84b34babe2352218c65f863602e013a8a55052e3f80a538efed865cc5fb7af558d168c52c5a399a4 + checksum: 10/56b60255a3ae23a378570a49c30d0c13bd74094c0509a978cad20ef57079c80bae91fd35749acb9ac5feef2922eec45a6fef8c0ee6e754cbf3722f8e5d0d771e languageName: node linkType: hard @@ -2827,21 +2835,21 @@ __metadata: linkType: hard "@metamask/eth-json-rpc-middleware@npm:^15.0.1": - version: 15.0.1 - resolution: "@metamask/eth-json-rpc-middleware@npm:15.0.1" + version: 15.1.2 + resolution: "@metamask/eth-json-rpc-middleware@npm:15.1.2" dependencies: - "@metamask/eth-block-tracker": "npm:^11.0.3" - "@metamask/eth-json-rpc-provider": "npm:^4.1.5" - "@metamask/eth-sig-util": "npm:^7.0.3" - "@metamask/json-rpc-engine": "npm:^10.0.0" - "@metamask/rpc-errors": "npm:^7.0.0" - "@metamask/utils": "npm:^9.1.0" + "@metamask/eth-block-tracker": "npm:^11.0.4" + "@metamask/eth-json-rpc-provider": "npm:^4.1.7" + "@metamask/eth-sig-util": "npm:^8.1.2" + "@metamask/json-rpc-engine": "npm:^10.0.2" + "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/utils": "npm:^11.0.1" "@types/bn.js": "npm:^5.1.5" bn.js: "npm:^5.2.1" klona: "npm:^2.0.6" pify: "npm:^5.0.0" safe-stable-stringify: "npm:^2.4.3" - checksum: 10/9777fca31440bf0076f5d2c24e2ddb4848ecd9d41b0a5d6114c27339567e60bfcb9057d6bfa81f18f5ca0ffa848ecf9603c765f606b8de206d3e34dba519c501 + checksum: 10/71e7d61cc58df250bfef73438a9e30cc2f78e0e979feb8a9c0be72bbad470a2fe068fa790194cb88ef56865e36156e525272bc3e1a2a7135d07f7bd81a752239 languageName: node linkType: hard @@ -3142,7 +3150,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/json-rpc-engine@npm:^10.0.0, @metamask/json-rpc-engine@npm:^10.0.1, @metamask/json-rpc-engine@npm:^10.0.2, @metamask/json-rpc-engine@workspace:packages/json-rpc-engine": +"@metamask/json-rpc-engine@npm:^10.0.0, @metamask/json-rpc-engine@npm:^10.0.2, @metamask/json-rpc-engine@workspace:packages/json-rpc-engine": version: 0.0.0-use.local resolution: "@metamask/json-rpc-engine@workspace:packages/json-rpc-engine" dependencies: @@ -3162,7 +3170,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/json-rpc-middleware-stream@npm:^8.0.5, @metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream": +"@metamask/json-rpc-middleware-stream@npm:^8.0.6, @metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream": version: 0.0.0-use.local resolution: "@metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream" dependencies: @@ -3185,16 +3193,16 @@ __metadata: languageName: unknown linkType: soft -"@metamask/key-tree@npm:^9.1.2": - version: 9.1.2 - resolution: "@metamask/key-tree@npm:9.1.2" +"@metamask/key-tree@npm:^10.0.2": + version: 10.0.2 + resolution: "@metamask/key-tree@npm:10.0.2" dependencies: "@metamask/scure-bip39": "npm:^2.1.1" - "@metamask/utils": "npm:^9.0.0" + "@metamask/utils": "npm:^11.0.1" "@noble/curves": "npm:^1.2.0" "@noble/hashes": "npm:^1.3.2" "@scure/base": "npm:^1.0.0" - checksum: 10/9b178a4156b2f36bf630564dd0530c41c6356492971d2bcc8f979c79c81144945823a5b770e4097e12b89b42133b81f00c95a7b8fe9931ea1dd928989ee3c406 + checksum: 10/fd2e445c75dc3cd3976fdc38a5029ee71a6f4afcbbf5c9a17152bba70cf35df8095caa853ae62eef90a51b43f23eeb9546fc6eb7d93a099d82effe8dc7592259 languageName: node linkType: hard @@ -3441,14 +3449,14 @@ __metadata: linkType: soft "@metamask/nonce-tracker@npm:^6.0.0": - version: 6.0.0 - resolution: "@metamask/nonce-tracker@npm:6.0.0" + version: 6.0.1 + resolution: "@metamask/nonce-tracker@npm:6.0.1" dependencies: "@ethersproject/providers": "npm:^5.7.2" - async-mutex: "npm:^0.3.1" + async-mutex: "npm:^0.5.0" peerDependencies: "@metamask/eth-block-tracker": ">=9" - checksum: 10/e62edd38eeaba6d917bc3aed38017294f2bfdb59120a9fb4f093fe96a46d8d9214453a802fe782faaf4a007f4cd5f393607c70a2ff8479ecd7ef18827cad067a + checksum: 10/3f0ba80be867e210dbde4b3cfef7d3b458217a2b744731efb9500c6223910c08e301c1d2c69a2502b0bf396ddd6bf5328d525acafb3613756aa1ae658948ec25 languageName: node linkType: hard @@ -3496,27 +3504,27 @@ __metadata: languageName: node linkType: hard -"@metamask/object-multiplex@npm:^2.0.0": - version: 2.0.0 - resolution: "@metamask/object-multiplex@npm:2.0.0" +"@metamask/object-multiplex@npm:^2.0.0, @metamask/object-multiplex@npm:^2.1.0": + version: 2.1.0 + resolution: "@metamask/object-multiplex@npm:2.1.0" dependencies: once: "npm:^1.4.0" readable-stream: "npm:^3.6.2" - checksum: 10/54baea752a3ac7c2742c376512e00d4902d383e9da8787574d3b21eb0081523309e24e3915a98f3ae0341d65712b6832d2eb7eeb862f4ef0da1ead52dcde5387 + checksum: 10/e119f695e89eb20c3174f8ac6d74587498d85cff92c37e83e167cb758b3d3147d5b5e1a997d6198d430ebcf2cede6265bf5d4513fe96dbb2d82bbc6167752caa languageName: node linkType: hard "@metamask/obs-store@npm:^9.0.0": - version: 9.0.0 - resolution: "@metamask/obs-store@npm:9.0.0" + version: 9.1.0 + resolution: "@metamask/obs-store@npm:9.1.0" dependencies: "@metamask/safe-event-emitter": "npm:^3.0.0" readable-stream: "npm:^3.6.2" - checksum: 10/1c202a5bbdc79a6b8b3fba946c09dc5521e87260956d30db6543e7bf3d95bd44ebd958f509e3e7332041845176487fe78d3b40bdedbc213061ba849fd978e468 + checksum: 10/fa37a0b9e1e25f54c93a8f16449b3fc771c15b70d79d590cf41e22f871a19d673bcfd0d08b044093235d10d0bb031b47b8209d89997def0cb256abe3e371064f languageName: node linkType: hard -"@metamask/permission-controller@npm:^11.0.3, @metamask/permission-controller@npm:^11.0.5, @metamask/permission-controller@workspace:packages/permission-controller": +"@metamask/permission-controller@npm:^11.0.5, @metamask/permission-controller@workspace:packages/permission-controller": version: 0.0.0-use.local resolution: "@metamask/permission-controller@workspace:packages/permission-controller" dependencies: @@ -3564,7 +3572,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/phishing-controller@npm:^12.0.2, @metamask/phishing-controller@workspace:packages/phishing-controller": +"@metamask/phishing-controller@npm:^12.3.1, @metamask/phishing-controller@workspace:packages/phishing-controller": version: 0.0.0-use.local resolution: "@metamask/phishing-controller@workspace:packages/phishing-controller" dependencies: @@ -3613,13 +3621,13 @@ __metadata: languageName: unknown linkType: soft -"@metamask/post-message-stream@npm:^8.1.1": - version: 8.1.1 - resolution: "@metamask/post-message-stream@npm:8.1.1" +"@metamask/post-message-stream@npm:^9.0.0": + version: 9.0.0 + resolution: "@metamask/post-message-stream@npm:9.0.0" dependencies: - "@metamask/utils": "npm:^9.0.0" + "@metamask/utils": "npm:^11.0.1" readable-stream: "npm:3.6.2" - checksum: 10/8218d321abe734522aefaf6b44e4203966c3feaf83e2de6e68eef9dbe92b7fb47fe7fd82eae362147b1d741cc58d78bcc95d8bf02058e260ad2fb978104c96cf + checksum: 10/5da711d3274e724452322939a5a77c60ed1d7ed73cdaa62e95c16debc443804d5a16de116dce742e05b3fbfa962e009dfeafc3a12a66f20e163617567f2cace5 languageName: node linkType: hard @@ -3687,16 +3695,16 @@ __metadata: languageName: unknown linkType: soft -"@metamask/providers@npm:^18.1.1": - version: 18.1.1 - resolution: "@metamask/providers@npm:18.1.1" +"@metamask/providers@npm:^18.1.1, @metamask/providers@npm:^18.3.1": + version: 18.3.1 + resolution: "@metamask/providers@npm:18.3.1" dependencies: - "@metamask/json-rpc-engine": "npm:^10.0.1" - "@metamask/json-rpc-middleware-stream": "npm:^8.0.5" + "@metamask/json-rpc-engine": "npm:^10.0.2" + "@metamask/json-rpc-middleware-stream": "npm:^8.0.6" "@metamask/object-multiplex": "npm:^2.0.0" - "@metamask/rpc-errors": "npm:^7.0.1" + "@metamask/rpc-errors": "npm:^7.0.2" "@metamask/safe-event-emitter": "npm:^3.1.1" - "@metamask/utils": "npm:^10.0.0" + "@metamask/utils": "npm:^11.0.1" detect-browser: "npm:^5.2.0" extension-port-stream: "npm:^4.1.0" fast-deep-equal: "npm:^3.1.3" @@ -3704,7 +3712,7 @@ __metadata: readable-stream: "npm:^3.6.2" peerDependencies: webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 - checksum: 10/dca428d84e490343d85921d4fb09216a0b64be59a036d7b4f7b5ca4e2581c29a4106d58ff9dfe0650dc2b9387dd2adad508fc61073a9fda8ebde8ee3a5137abe + checksum: 10/0e21ba9cce926a49dedbfe30fc964cd2349ee6bf9156f525fb894dcbc147a3ae480384884131a6b1a0a508989b547d8c8d2aeb3d10e11f67a8ee5230c45631a8 languageName: node linkType: hard @@ -3778,7 +3786,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/rpc-errors@npm:^7.0.0, @metamask/rpc-errors@npm:^7.0.1, @metamask/rpc-errors@npm:^7.0.2": +"@metamask/rpc-errors@npm:^7.0.0, @metamask/rpc-errors@npm:^7.0.2": version: 7.0.2 resolution: "@metamask/rpc-errors@npm:7.0.2" dependencies: @@ -3789,9 +3797,9 @@ __metadata: linkType: hard "@metamask/safe-event-emitter@npm:^3.0.0, @metamask/safe-event-emitter@npm:^3.1.1": - version: 3.1.1 - resolution: "@metamask/safe-event-emitter@npm:3.1.1" - checksum: 10/e24db4d7c20764bfc5b025065f92518c805f0ffb1da4820078b8cff7dcae964c0f354cf053fcb7ac659de015d5ffdf21aae5e8d44e191ee8faa9066855f22653 + version: 3.1.2 + resolution: "@metamask/safe-event-emitter@npm:3.1.2" + checksum: 10/8ef7579f9317eb5c94ecf3e6abb8d13b119af274b678805eac76abe4c0667bfdf539f385e552bb973e96333b71b77aa7c787cb3fce9cd5fb4b00f1dbbabf880d languageName: node linkType: hard @@ -3864,107 +3872,111 @@ __metadata: languageName: unknown linkType: soft -"@metamask/slip44@npm:^4.0.0": - version: 4.0.0 - resolution: "@metamask/slip44@npm:4.0.0" - checksum: 10/3e47e8834b0fbdabe1f126fd78665767847ddc1f9ccc8defb23007dd71fcd2e4899c8ca04857491be3630668a3765bad1e40fdfca9a61ef33236d8d08e51535e +"@metamask/slip44@npm:^4.1.0": + version: 4.1.0 + resolution: "@metamask/slip44@npm:4.1.0" + checksum: 10/4265254a1800a24915bd1de15f86f196737132f9af2a084c2efc885decfc5dd87ad8f0687269d90b35e2ec64d3ea4fbff0caa793bcea6e585b1f3a290952b750 languageName: node linkType: hard "@metamask/snaps-controllers@npm:^9.10.0": - version: 9.12.0 - resolution: "@metamask/snaps-controllers@npm:9.12.0" + version: 9.17.0 + resolution: "@metamask/snaps-controllers@npm:9.17.0" dependencies: - "@metamask/approval-controller": "npm:^7.1.1" - "@metamask/base-controller": "npm:^7.0.2" - "@metamask/json-rpc-engine": "npm:^10.0.1" - "@metamask/json-rpc-middleware-stream": "npm:^8.0.5" - "@metamask/object-multiplex": "npm:^2.0.0" - "@metamask/permission-controller": "npm:^11.0.3" - "@metamask/phishing-controller": "npm:^12.0.2" - "@metamask/post-message-stream": "npm:^8.1.1" - "@metamask/rpc-errors": "npm:^7.0.1" - "@metamask/snaps-registry": "npm:^3.2.2" - "@metamask/snaps-rpc-methods": "npm:^11.5.1" - "@metamask/snaps-sdk": "npm:^6.10.0" - "@metamask/snaps-utils": "npm:^8.5.0" - "@metamask/utils": "npm:^10.0.0" + "@metamask/approval-controller": "npm:^7.1.2" + "@metamask/base-controller": "npm:^7.0.3" + "@metamask/json-rpc-engine": "npm:^10.0.2" + "@metamask/json-rpc-middleware-stream": "npm:^8.0.6" + "@metamask/key-tree": "npm:^10.0.2" + "@metamask/object-multiplex": "npm:^2.1.0" + "@metamask/permission-controller": "npm:^11.0.5" + "@metamask/phishing-controller": "npm:^12.3.1" + "@metamask/post-message-stream": "npm:^9.0.0" + "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/snaps-registry": "npm:^3.2.3" + "@metamask/snaps-rpc-methods": "npm:^11.9.0" + "@metamask/snaps-sdk": "npm:^6.15.0" + "@metamask/snaps-utils": "npm:^8.8.0" + "@metamask/utils": "npm:^11.0.1" "@xstate/fsm": "npm:^2.0.0" + async-mutex: "npm:^0.5.0" browserify-zlib: "npm:^0.2.0" concat-stream: "npm:^2.0.0" fast-deep-equal: "npm:^3.1.3" get-npm-tarball-url: "npm:^2.0.3" immer: "npm:^9.0.6" + luxon: "npm:^3.5.0" nanoid: "npm:^3.1.31" readable-stream: "npm:^3.6.2" readable-web-to-node-stream: "npm:^3.0.2" semver: "npm:^7.5.4" tar-stream: "npm:^3.1.7" peerDependencies: - "@metamask/snaps-execution-environments": ^6.9.2 + "@metamask/snaps-execution-environments": ^6.12.0 peerDependenciesMeta: "@metamask/snaps-execution-environments": optional: true - checksum: 10/8d411ff2cfd43e62fe780092e935a1d977379488407b56cca1390edfa9408871cbaf3599f6e6ee999340d46fd3650f225a3270ceec9492c6f2dc4d93538c25ae + checksum: 10/c09eb4a31e685a9fbe41f2b407d9037785e572a7ef135ecfbede3cf015eaa87bef53c17e615a85ad8bbb757d8baf969cd14766dc70c04aa7645ef819ef03417d languageName: node linkType: hard -"@metamask/snaps-registry@npm:^3.2.2": - version: 3.2.2 - resolution: "@metamask/snaps-registry@npm:3.2.2" +"@metamask/snaps-registry@npm:^3.2.3": + version: 3.2.3 + resolution: "@metamask/snaps-registry@npm:3.2.3" dependencies: "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^10.0.0" + "@metamask/utils": "npm:^11.0.1" "@noble/curves": "npm:^1.2.0" "@noble/hashes": "npm:^1.3.2" - checksum: 10/ca8239e838bbb913435e166136bbc9bd7222c4bd87b1525fa7ae3cdf2e0b868b5d4d90a67d1ed49633d566bdef9243abdbf5f5937b85a85d24184087f555813e + checksum: 10/37760f29b7aaa337d815cf0c11fa34af5093d87fdc60a3750c494cf8bae6293cd52da03e7694b467b79733052d75ec6e3781ab3590d7259a050784e5be347d12 languageName: node linkType: hard -"@metamask/snaps-rpc-methods@npm:^11.5.1": - version: 11.5.1 - resolution: "@metamask/snaps-rpc-methods@npm:11.5.1" +"@metamask/snaps-rpc-methods@npm:^11.9.0": + version: 11.9.0 + resolution: "@metamask/snaps-rpc-methods@npm:11.9.0" dependencies: - "@metamask/key-tree": "npm:^9.1.2" - "@metamask/permission-controller": "npm:^11.0.3" - "@metamask/rpc-errors": "npm:^7.0.1" - "@metamask/snaps-sdk": "npm:^6.10.0" - "@metamask/snaps-utils": "npm:^8.5.0" + "@metamask/key-tree": "npm:^10.0.2" + "@metamask/permission-controller": "npm:^11.0.5" + "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/snaps-sdk": "npm:^6.15.0" + "@metamask/snaps-utils": "npm:^8.8.0" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^10.0.0" + "@metamask/utils": "npm:^11.0.1" "@noble/hashes": "npm:^1.3.1" - checksum: 10/0f999a5dd64f1b1123366f448ae833f0e95a415791600bb535959ba67d2269fbe3c4504d47f04db71bafa79a9a87d6b832fb2e2b5ef29567078c95bce2638f35 + luxon: "npm:^3.5.0" + checksum: 10/44d47d3d8dcaa349863f2df2622c6fedc15e56e77d00ee97caadf3cebef6ddca06c8d4fa199b196a067bbdce59ec9a867446c133658b098216746bc23e7245f8 languageName: node linkType: hard -"@metamask/snaps-sdk@npm:^6.10.0, @metamask/snaps-sdk@npm:^6.11.0, @metamask/snaps-sdk@npm:^6.7.0": - version: 6.11.0 - resolution: "@metamask/snaps-sdk@npm:6.11.0" +"@metamask/snaps-sdk@npm:^6.15.0, @metamask/snaps-sdk@npm:^6.7.0": + version: 6.15.0 + resolution: "@metamask/snaps-sdk@npm:6.15.0" dependencies: - "@metamask/key-tree": "npm:^9.1.2" - "@metamask/providers": "npm:^18.1.1" - "@metamask/rpc-errors": "npm:^7.0.1" + "@metamask/key-tree": "npm:^10.0.2" + "@metamask/providers": "npm:^18.3.1" + "@metamask/rpc-errors": "npm:^7.0.2" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^10.0.0" - checksum: 10/0f9b507139d1544b1b3d85ff8de81b800d543012d3ee9414c607c23abe9562e0dca48de089ed94be69f5ad981730a0f443371edfe6bc2d5ffb140b28e437bfd2 + "@metamask/utils": "npm:^11.0.1" + checksum: 10/0e561a0b3ae96521efbdb7223a46e42a634f84a61f271288b5c549ccc2a974247100925d551b359bd84d76aec75529dff726176e5379f446721c48f702cf2598 languageName: node linkType: hard -"@metamask/snaps-utils@npm:^8.3.0, @metamask/snaps-utils@npm:^8.5.0": - version: 8.6.0 - resolution: "@metamask/snaps-utils@npm:8.6.0" +"@metamask/snaps-utils@npm:^8.3.0, @metamask/snaps-utils@npm:^8.8.0": + version: 8.8.0 + resolution: "@metamask/snaps-utils@npm:8.8.0" dependencies: "@babel/core": "npm:^7.23.2" "@babel/types": "npm:^7.23.0" - "@metamask/base-controller": "npm:^7.0.2" - "@metamask/key-tree": "npm:^9.1.2" - "@metamask/permission-controller": "npm:^11.0.3" - "@metamask/rpc-errors": "npm:^7.0.1" - "@metamask/slip44": "npm:^4.0.0" - "@metamask/snaps-registry": "npm:^3.2.2" - "@metamask/snaps-sdk": "npm:^6.11.0" + "@metamask/base-controller": "npm:^7.0.3" + "@metamask/key-tree": "npm:^10.0.2" + "@metamask/permission-controller": "npm:^11.0.5" + "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/slip44": "npm:^4.1.0" + "@metamask/snaps-registry": "npm:^3.2.3" + "@metamask/snaps-sdk": "npm:^6.15.0" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^10.0.0" + "@metamask/utils": "npm:^11.0.1" "@noble/hashes": "npm:^1.3.1" "@scure/base": "npm:^1.1.1" chalk: "npm:^4.1.2" @@ -3977,7 +3989,7 @@ __metadata: semver: "npm:^7.5.4" ses: "npm:^1.1.0" validate-npm-package-name: "npm:^5.0.0" - checksum: 10/c0f538f3f95e1875f6557b6ecc32f981bc4688d581af8cdc62c6c3ab8951c138286cd0b2d1cd82f769df24fcec10f71dcda67ae9a47edcff9ff73d52672df191 + checksum: 10/567354cf09dc74fe392e281e836325bfec570428dd77101935fa443bcc987bfdee6a568a572b92269639fda30a7f02ff1047ad887aed52b73709ab7a6bf1cddd languageName: node linkType: hard @@ -4088,23 +4100,6 @@ __metadata: languageName: unknown linkType: soft -"@metamask/utils@npm:^10.0.0": - version: 10.0.0 - resolution: "@metamask/utils@npm:10.0.0" - dependencies: - "@ethereumjs/tx": "npm:^4.2.0" - "@metamask/superstruct": "npm:^3.1.0" - "@noble/hashes": "npm:^1.3.1" - "@scure/base": "npm:^1.1.3" - "@types/debug": "npm:^4.1.7" - debug: "npm:^4.3.4" - pony-cause: "npm:^2.1.10" - semver: "npm:^7.5.4" - uuid: "npm:^9.0.1" - checksum: 10/9c2e6421f685d8a45145b6026a6f9fd0701eb5a2e8490fc6d18e64c103d5a62097f301cbc797790da52ceb5853bd9f65845c934b00299e69e5e6736c52b32f0f - languageName: node - linkType: hard - "@metamask/utils@npm:^11.0.1": version: 11.0.1 resolution: "@metamask/utils@npm:11.0.1" @@ -4197,11 +4192,11 @@ __metadata: linkType: hard "@noble/curves@npm:^1.2.0": - version: 1.5.0 - resolution: "@noble/curves@npm:1.5.0" + version: 1.8.0 + resolution: "@noble/curves@npm:1.8.0" dependencies: - "@noble/hashes": "npm:1.4.0" - checksum: 10/d7707d756a887a0daf9eba709526017ac6905d4be58760947e0f0652961926295ba62a5a699d9a9f0bf2a2e0c6803381373e14542be5ff3885b3434bb59be86c + "@noble/hashes": "npm:1.7.0" + checksum: 10/c54ce84cf54b8bda1a37a10dfae2e49e5b6cdf5dd98b399efa8b8a80a286b3f8f27bde53202cb308353bfd98719938991a78bed6e43f81f13b17f8181b7b82eb languageName: node linkType: hard @@ -4212,13 +4207,20 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:~1.4.0": +"@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 10/e156e65794c473794c52fa9d06baf1eb20903d0d96719530f523cc4450f6c721a957c544796e6efd0197b2296e7cd70efeb312f861465e17940a3e3c7e0febc6 languageName: node linkType: hard +"@noble/hashes@npm:1.7.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.4.0": + version: 1.7.0 + resolution: "@noble/hashes@npm:1.7.0" + checksum: 10/ab038a816c8c9bb986e92797e3d9c5a5b37c020e0c3edc55bcae5061dbdd457f1f0a22787f83f4787c17415ba0282a20a1e455d36ed0cdcace4ce21ef1869f60 + languageName: node + linkType: hard + "@noble/hashes@npm:~1.3.2": version: 1.3.3 resolution: "@noble/hashes@npm:1.3.3" @@ -4273,6 +4275,19 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/agent@npm:3.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10/775c9a7eb1f88c195dfb3bce70c31d0fe2a12b28b754e25c08a3edb4bc4816bfedb7ac64ef1e730579d078ca19dacf11630e99f8f3c3e0fd7b23caa5fd6d30a6 + languageName: node + linkType: hard + "@npmcli/fs@npm:^3.1.0": version: 3.1.1 resolution: "@npmcli/fs@npm:3.1.1" @@ -4282,6 +4297,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10/405c4490e1ff11cf299775449a3c254a366a4b1ffc79d87159b0ee7d5558ac9f6a2f8c0735fd6ff3873cef014cb1a44a5f9127cb6a1b2dbc408718cca9365b5a + languageName: node + linkType: hard + "@npmcli/git@npm:^5.0.0": version: 5.0.8 resolution: "@npmcli/git@npm:5.0.8" @@ -4307,8 +4331,8 @@ __metadata: linkType: hard "@npmcli/package-json@npm:^5.0.0": - version: 5.2.0 - resolution: "@npmcli/package-json@npm:5.2.0" + version: 5.2.1 + resolution: "@npmcli/package-json@npm:5.2.1" dependencies: "@npmcli/git": "npm:^5.0.0" glob: "npm:^10.2.2" @@ -4317,7 +4341,7 @@ __metadata: normalize-package-data: "npm:^6.0.0" proc-log: "npm:^4.0.0" semver: "npm:^7.5.3" - checksum: 10/c3d2218877bfc005bca3b7a11f53825bf16a68811b8e8ed0c9b219cceb8e8e646d70efab8c5d6decbd8007f286076468b3f456dab4d41d648aff73a5f3a6fce2 + checksum: 10/304a819b93f79a6e0e56cb371961a66d2db72142e310d545ecbbbe4d917025a30601aa8e63a5f0cc28f0fe281c116bdaf79b334619b105a1d027a2b769ecd137 languageName: node linkType: hard @@ -4456,10 +4480,17 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": - version: 1.1.7 - resolution: "@scure/base@npm:1.1.7" - checksum: 10/fc50ffaab36cb46ff9fa4dc5052a06089ab6a6707f63d596bb34aaaec76173c9a564ac312a0b981b5e7a5349d60097b8878673c75d6cbfc4da7012b63a82099b +"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3": + version: 1.2.1 + resolution: "@scure/base@npm:1.2.1" + checksum: 10/f7bdd17618ccae7a74c8cbe410a235e4adbe54aa8afe4e2fb1294338aa92f6fd04b1f1f5dea60552f638b5f5e3e74902b7baf59d3954e5e42c0a36c6baa2ebe0 + languageName: node + linkType: hard + +"@scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": + version: 1.1.9 + resolution: "@scure/base@npm:1.1.9" + checksum: 10/f0ab7f687bbcdee2a01377fe3cd808bf63977999672751295b6a92625d5322f4754a96d40f6bd579bc367aad48ecf8a4e6d0390e70296e6ded1076f52adb16bb languageName: node linkType: hard @@ -4617,8 +4648,8 @@ __metadata: linkType: hard "@ts-bridge/cli@npm:^0.6.1": - version: 0.6.1 - resolution: "@ts-bridge/cli@npm:0.6.1" + version: 0.6.2 + resolution: "@ts-bridge/cli@npm:0.6.2" dependencies: "@ts-bridge/resolver": "npm:^0.2.0" chalk: "npm:^5.3.0" @@ -4629,7 +4660,7 @@ __metadata: bin: ts-bridge: ./dist/index.js tsbridge: ./dist/index.js - checksum: 10/1cbb8fbfc7f58b804553ab9bc06b689b409d4cdd0f1e960a0ea87971ec7885b5ee2a86cb192d955c7d3611afcadb960e7dfee66aeca60f798a70e7f97aa969c3 + checksum: 10/df690edb0c78eaa91bea93582d628ef3ee0b2555fc27f9fc12ee1eb29d681b387ba76788359190ec330e29d8a31ba8974d2420d2b8dc16adc28c669a18f76de1 languageName: node linkType: hard @@ -4710,11 +4741,11 @@ __metadata: linkType: hard "@types/bn.js@npm:^5.1.0, @types/bn.js@npm:^5.1.5": - version: 5.1.5 - resolution: "@types/bn.js@npm:5.1.5" + version: 5.1.6 + resolution: "@types/bn.js@npm:5.1.6" dependencies: "@types/node": "npm:*" - checksum: 10/9719330c86aeae0a6a447c974cf0f853ba3660ede20de61f435b03d699e30e6d8b35bf71a8dc9fdc8317784438e83177644ba068ed653d0ae0106e1ecbfe289e + checksum: 10/db565b5a2af59b09459d74441153bf23a0e80f1fb2d070330786054e7ce1a7285dc40afcd8f289426c61a83166bdd70814f70e2d439744686aac5d3ea75daf13 languageName: node linkType: hard @@ -4828,12 +4859,12 @@ __metadata: linkType: hard "@types/jest@npm:*": - version: 29.5.12 - resolution: "@types/jest@npm:29.5.12" + version: 29.5.14 + resolution: "@types/jest@npm:29.5.14" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: 10/312e8dcf92cdd5a5847d6426f0940829bca6fe6b5a917248f3d7f7ef5d85c9ce78ef05e47d2bbabc40d41a930e0e36db2d443d2610a9e3db9062da2d5c904211 + checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b languageName: node linkType: hard @@ -4864,9 +4895,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.191": - version: 4.17.7 - resolution: "@types/lodash@npm:4.17.7" - checksum: 10/b8177f19cf962414a66989837481b13f546afc2e98e8d465bec59e6ac03a59c584eb7053ce511cde3a09c5f3096d22a5ae22cfb56b23f3b0da75b0743b6b1a44 + version: 4.17.14 + resolution: "@types/lodash@npm:4.17.14" + checksum: 10/6ee40725f3e192f5ef1f493caca19210aa7acd7adc3136b8dba84d418a35be0abea0668105aed9f696ad62a54310a9c0d328971ad4b157f5bcda700424ed5aae languageName: node linkType: hard @@ -4885,34 +4916,36 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": - version: 22.5.0 - resolution: "@types/node@npm:22.5.0" + version: 22.10.6 + resolution: "@types/node@npm:22.10.6" dependencies: - undici-types: "npm:~6.19.2" - checksum: 10/89af3bd217b1559b645a9ed16d4ae3add75749814cbd8eefddd1b96003d1973afb1c8a2b23d69f3a8cc6c532e3aa185eaf5cc29a6e7c42c311a2aad4c99430ae + undici-types: "npm:~6.20.0" + checksum: 10/ac93c9b6337ddb70176abade1ca4cdec24cde93cfc19023f3e001d80cb42f1d3c2487dd1626ce016985953319de30528d9e73dc5c6e2e28be9eaa9ec0237fc1d languageName: node linkType: hard -"@types/node@npm:18.15.13": - version: 18.15.13 - resolution: "@types/node@npm:18.15.13" - checksum: 10/b9bbe923573797ef7c5fd2641a6793489e25d9369c32aeadcaa5c7c175c85b42eb12d6fe173f6781ab6f42eaa1ebd9576a419eeaa2a1ec810094adb8adaa9a54 +"@types/node@npm:22.7.5": + version: 22.7.5 + resolution: "@types/node@npm:22.7.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10/e8ba102f8c1aa7623787d625389be68d64e54fcbb76d41f6c2c64e8cf4c9f4a2370e7ef5e5f1732f3c57529d3d26afdcb2edc0101c5e413a79081449825c57ac languageName: node linkType: hard "@types/node@npm:^16.18.54": - version: 16.18.106 - resolution: "@types/node@npm:16.18.106" - checksum: 10/1970719a048bfc56554f8e132e8e5292c197d6e023d334190b0d3817a05a12bfb6537eaa24778ddb695d2073195f0545e5a4b6bcaf81b656994bbca39f349c3b + version: 16.18.123 + resolution: "@types/node@npm:16.18.123" + checksum: 10/461cb72845a539941e38720362a391e873b5ae26c8eabc04252ed883a165d15281cc7a45da7a47b3c4e7b8cf59da8a2d9025aae9b9b74ecfdc7d3147a638a6c0 languageName: node linkType: hard "@types/node@npm:^18.17.15": - version: 18.19.68 - resolution: "@types/node@npm:18.19.68" + version: 18.19.70 + resolution: "@types/node@npm:18.19.70" dependencies: undici-types: "npm:~5.26.4" - checksum: 10/024a4a8eeca21c0d1eaa575036dbc44528eae180821de71b77868ddc24d18032b988582046db4f7ea2643970a5169d790e1884153472145de07d629bc2ce2ec6 + checksum: 10/374abb7e75f7f8b2418cde5b0a8dae0032d4e1e3a76097a507a90ed9e66e40c12d19b75493db3aa9d4f92b03ae90d7d9f67c7d64c7f73f20145577350adf0e9b languageName: node linkType: hard @@ -5066,15 +5099,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.19.1, @typescript-eslint/eslint-plugin@npm:^8.7.0": - version: 8.19.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.19.1" +"@typescript-eslint/eslint-plugin@npm:8.20.0, @typescript-eslint/eslint-plugin@npm:^8.7.0": + version: 8.20.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.20.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/type-utils": "npm:8.19.1" - "@typescript-eslint/utils": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/scope-manager": "npm:8.20.0" + "@typescript-eslint/type-utils": "npm:8.20.0" + "@typescript-eslint/utils": "npm:8.20.0" + "@typescript-eslint/visitor-keys": "npm:8.20.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -5083,64 +5116,64 @@ __metadata: "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/c9a6d3181ec01068075b85ad3ac454910b4452281d60c775cc7229827f6d6a076b7336f5f07a7ad89bf08b3224f6a49aa20342b9438702393bee0aa7315d23b2 + checksum: 10/9f027dc0eb7b4b0afed41a6f16a731321fb45b621722ddc68d6c87c708021f10cb84efbb6bacc75c91e60a7619c9957bc9ed557bfb5925900b866ef7d6d6b8a2 languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.19.1, @typescript-eslint/parser@npm:^8.7.0": - version: 8.19.1 - resolution: "@typescript-eslint/parser@npm:8.19.1" +"@typescript-eslint/parser@npm:8.20.0, @typescript-eslint/parser@npm:^8.7.0": + version: 8.20.0 + resolution: "@typescript-eslint/parser@npm:8.20.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/typescript-estree": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/scope-manager": "npm:8.20.0" + "@typescript-eslint/types": "npm:8.20.0" + "@typescript-eslint/typescript-estree": "npm:8.20.0" + "@typescript-eslint/visitor-keys": "npm:8.20.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/da3db63ff655cf0fb91745ba8e52d853386f601cf6106d36f4541efcb9e2c6c3b82c6743b15680eff9eafeccaf31c9b26191a955e66ae19de9172f67335463ab + checksum: 10/52960498961d0927e9dc60f724e9df6445357db06133a7c00cc840823d92c8dd9f0b47cebc026aef12c316748732e5c04ca61861db05d2264cf53ab88fdb34e9 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.19.1, @typescript-eslint/scope-manager@npm:^8.1.0": - version: 8.19.1 - resolution: "@typescript-eslint/scope-manager@npm:8.19.1" +"@typescript-eslint/scope-manager@npm:8.20.0, @typescript-eslint/scope-manager@npm:^8.1.0": + version: 8.20.0 + resolution: "@typescript-eslint/scope-manager@npm:8.20.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" - checksum: 10/6ffc78b15367f211eb6650459ca2bb6bfe4c1fa95a3474adc08ee9a20c250b2e0e02fd99be36bd3dad74967ecd9349e792b5d818d85735cba40f1b5c236074d1 + "@typescript-eslint/types": "npm:8.20.0" + "@typescript-eslint/visitor-keys": "npm:8.20.0" + checksum: 10/0ea30ba12007d77659b43bbbec463c142d3d4d36f7de381d1f59a97f95240203e79dd9a24040be7113eb4c8bd231339f9322d9a40e1a1fb178e9ac52d9c559ab languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/type-utils@npm:8.19.1" +"@typescript-eslint/type-utils@npm:8.20.0": + version: 8.20.0 + resolution: "@typescript-eslint/type-utils@npm:8.20.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.19.1" - "@typescript-eslint/utils": "npm:8.19.1" + "@typescript-eslint/typescript-estree": "npm:8.20.0" + "@typescript-eslint/utils": "npm:8.20.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^2.0.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/123ecda88b057d6a4b68226701f435661440a420fda88cba60b49d7fb3e4f49483164ff174f259e28c0beabb0ed04500462a20faefd78331ba202bf54b01e3ef + checksum: 10/cdde9d30e684c0c44434ed97e11c962d8f80f53b8a0050e8fe10b7f20c26f7684a340acd21c83bdcbc1feb3eef334eb5b0fef31d2d330648e52d4afe57942a95 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/types@npm:8.19.1" - checksum: 10/5833a5f8fdac4a490dd3906a0243a0713fbf138fabb451870c70b0b089c539a9624b467b0913ddc0a225a8284342e7fd31cd506dec53c1a6d8f3c8c8902b9cae +"@typescript-eslint/types@npm:8.20.0": + version: 8.20.0 + resolution: "@typescript-eslint/types@npm:8.20.0" + checksum: 10/434859226136ea9e439e8abf5dcf813ea3b55b7e4af6ecc8d290a2f925e3baad0579765ac32d21005b0caedaac38b8624131f87b572c84ca92ac3e742a52e149 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.19.1" +"@typescript-eslint/typescript-estree@npm:8.20.0": + version: 8.20.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.20.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/types": "npm:8.20.0" + "@typescript-eslint/visitor-keys": "npm:8.20.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" @@ -5149,32 +5182,32 @@ __metadata: ts-api-utils: "npm:^2.0.0" peerDependencies: typescript: ">=4.8.4 <5.8.0" - checksum: 10/5de467452d5ef1a380d441b06cd0134652a0c98cdb4ce31b93eb589f7dc75ef60364d03fd80ca0a48d0c8b268f7258d4f6528b16fe1b89442d60a4bc960fe5f5 + checksum: 10/8dbb1b835492574b4c8765c64964179e258f811d3f4cd7f6a90e1cb297520090728f77366cfb05233c26f4c07b1f2be990fa3f54eae9e7abc218005d51ee6804 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.19.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": - version: 8.19.1 - resolution: "@typescript-eslint/utils@npm:8.19.1" +"@typescript-eslint/utils@npm:8.20.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": + version: 8.20.0 + resolution: "@typescript-eslint/utils@npm:8.20.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/typescript-estree": "npm:8.19.1" + "@typescript-eslint/scope-manager": "npm:8.20.0" + "@typescript-eslint/types": "npm:8.20.0" + "@typescript-eslint/typescript-estree": "npm:8.20.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/bb92116a53fe143ee87e830941afb21d4222a64ca3f2b6dac5c2d9984f981408e60e52b04c32d95208896075ac222fb4ee631c5b0c4826b87d4bd8091c421ab1 + checksum: 10/d4369f3e535d5c75eedce2b8f4ea1e857b75ac2ea73f2c707ba3fa3533053f63d8c22f085e58573a2d035d61ed69f6fef4ba0bc7c7df173d26b3adce73bf6aed languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.19.1" +"@typescript-eslint/visitor-keys@npm:8.20.0": + version: 8.20.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.20.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/types": "npm:8.20.0" eslint-visitor-keys: "npm:^4.2.0" - checksum: 10/510eb196e7b7d59d3981d672a75454615159e931fe78e2a64b09607c3cfa45110709b0eb5ac3dd271d757a0d98cf4868ad2f45bf9193f96e9efec3efa92a19c1 + checksum: 10/31f32efb975a10cb1b0028a6d0f47b65acb322ed446f93862e39a3a0d5b55a2354ab0f062794fb148f45c8ce09fb93878d8a101a72d09d4a06ffa2f0d163d65f languageName: node linkType: hard @@ -5185,60 +5218,60 @@ __metadata: languageName: node linkType: hard -"@vue/compiler-core@npm:3.4.38": - version: 3.4.38 - resolution: "@vue/compiler-core@npm:3.4.38" +"@vue/compiler-core@npm:3.5.13": + version: 3.5.13 + resolution: "@vue/compiler-core@npm:3.5.13" dependencies: - "@babel/parser": "npm:^7.24.7" - "@vue/shared": "npm:3.4.38" + "@babel/parser": "npm:^7.25.3" + "@vue/shared": "npm:3.5.13" entities: "npm:^4.5.0" estree-walker: "npm:^2.0.2" source-map-js: "npm:^1.2.0" - checksum: 10/16449e9083c290e6c13e1cc0cb0a0a457817a52533d10902388c872fb1337ba0fa29fb7b8394df5a10f5ed3bad264d6c386f9eaf47c07982a543f277dbee9b8a + checksum: 10/22f042bb47c8a1edb9d602e24da8092ab542d5640f0459a9b99ecf35f90e96678f870209dd30f774f5340c6d817d3c5a46ca49cefb9659ee5b228bd42d1f076a languageName: node linkType: hard -"@vue/compiler-dom@npm:3.4.38": - version: 3.4.38 - resolution: "@vue/compiler-dom@npm:3.4.38" +"@vue/compiler-dom@npm:3.5.13": + version: 3.5.13 + resolution: "@vue/compiler-dom@npm:3.5.13" dependencies: - "@vue/compiler-core": "npm:3.4.38" - "@vue/shared": "npm:3.4.38" - checksum: 10/4012fab212dc0628ef72f5ae13aa2dd551efb8be7f2aa8abe2a1db15058ddda29912a1e3aa1fc6712e2d8efe84724f16a907ad2cda987631bfc79330afc8d451 + "@vue/compiler-core": "npm:3.5.13" + "@vue/shared": "npm:3.5.13" + checksum: 10/5dc628c52091264a443c2d7326b759d7d3999c7e9c00078c2eb370b778e60b9f2ef258a8decf2fd97c8fa0923f895d449eabc1e5bc3d8a45d3ef99c9eb0599d7 languageName: node linkType: hard "@vue/compiler-sfc@npm:^3.3.4": - version: 3.4.38 - resolution: "@vue/compiler-sfc@npm:3.4.38" - dependencies: - "@babel/parser": "npm:^7.24.7" - "@vue/compiler-core": "npm:3.4.38" - "@vue/compiler-dom": "npm:3.4.38" - "@vue/compiler-ssr": "npm:3.4.38" - "@vue/shared": "npm:3.4.38" + version: 3.5.13 + resolution: "@vue/compiler-sfc@npm:3.5.13" + dependencies: + "@babel/parser": "npm:^7.25.3" + "@vue/compiler-core": "npm:3.5.13" + "@vue/compiler-dom": "npm:3.5.13" + "@vue/compiler-ssr": "npm:3.5.13" + "@vue/shared": "npm:3.5.13" estree-walker: "npm:^2.0.2" - magic-string: "npm:^0.30.10" - postcss: "npm:^8.4.40" + magic-string: "npm:^0.30.11" + postcss: "npm:^8.4.48" source-map-js: "npm:^1.2.0" - checksum: 10/3eec1ddc03e06a162087dbbff9679f941ff34c43e553006aa2717c6a396445f488b62b89afa9cf65688468a05d8517bf1ee64936ad78d7ba6647a850a089e0e0 + checksum: 10/08d55bbdbe86ad0a1fc0501dbf5f535161d35ecb378adb478dd4a75b97e8d21852516966c0ad8aed1d6da11b0d8280b7848ff142b4181cb8f24eaaecd7827f73 languageName: node linkType: hard -"@vue/compiler-ssr@npm:3.4.38": - version: 3.4.38 - resolution: "@vue/compiler-ssr@npm:3.4.38" +"@vue/compiler-ssr@npm:3.5.13": + version: 3.5.13 + resolution: "@vue/compiler-ssr@npm:3.5.13" dependencies: - "@vue/compiler-dom": "npm:3.4.38" - "@vue/shared": "npm:3.4.38" - checksum: 10/3ee052c8f10bf18db5d6788df21105698c139fac1de6c82532878cca86be4d052510a216184b3ea73331d84befcefd3f9ada11470c862f03696fed96ce1005cb + "@vue/compiler-dom": "npm:3.5.13" + "@vue/shared": "npm:3.5.13" + checksum: 10/09f2706455a7d8a5acc67c98120d28d0105d006184402b045636be7791939f5a77fd1c37657047b0129fa431f03437dcab9befc6baa172367ecdef7618407149 languageName: node linkType: hard -"@vue/shared@npm:3.4.38": - version: 3.4.38 - resolution: "@vue/shared@npm:3.4.38" - checksum: 10/46bfc1f3932fd154ff84dcd267cae4db730c98db433c848d40c9c0dc23dcabdb5efe96a3a378c9ed3b7e8281ca17e2753f0ce98ae43b54b315550dfaccb56868 +"@vue/shared@npm:3.5.13": + version: 3.5.13 + resolution: "@vue/shared@npm:3.5.13" + checksum: 10/5c0c24f443533392dde08c3e4272ff2e19af9762f90baeaa808850e05106537bbd9e2d2ad2081d979b8c4bc89902395b46036b67f74c60b76025924de37833b1 languageName: node linkType: hard @@ -5250,17 +5283,17 @@ __metadata: linkType: hard "@yarnpkg/cli@npm:^4.5.3": - version: 4.5.3 - resolution: "@yarnpkg/cli@npm:4.5.3" + version: 4.6.0 + resolution: "@yarnpkg/cli@npm:4.6.0" dependencies: - "@yarnpkg/core": "npm:^4.1.6" + "@yarnpkg/core": "npm:^4.2.0" "@yarnpkg/fslib": "npm:^3.1.1" "@yarnpkg/libzip": "npm:^3.1.0" "@yarnpkg/parsers": "npm:^3.0.2" "@yarnpkg/plugin-compat": "npm:^4.0.10" "@yarnpkg/plugin-constraints": "npm:^4.0.2" "@yarnpkg/plugin-dlx": "npm:^4.0.0" - "@yarnpkg/plugin-essentials": "npm:^4.2.2" + "@yarnpkg/plugin-essentials": "npm:^4.3.0" "@yarnpkg/plugin-exec": "npm:^3.0.0" "@yarnpkg/plugin-file": "npm:^3.0.0" "@yarnpkg/plugin-git": "npm:^3.1.0" @@ -5274,12 +5307,12 @@ __metadata: "@yarnpkg/plugin-npm-cli": "npm:^4.0.4" "@yarnpkg/plugin-pack": "npm:^4.0.0" "@yarnpkg/plugin-patch": "npm:^4.0.1" - "@yarnpkg/plugin-pnp": "npm:^4.0.5" + "@yarnpkg/plugin-pnp": "npm:^4.0.6" "@yarnpkg/plugin-pnpm": "npm:^2.0.0" "@yarnpkg/plugin-stage": "npm:^4.0.0" "@yarnpkg/plugin-typescript": "npm:^4.1.1" "@yarnpkg/plugin-version": "npm:^4.0.4" - "@yarnpkg/plugin-workspace-tools": "npm:^4.1.1" + "@yarnpkg/plugin-workspace-tools": "npm:^4.1.2" "@yarnpkg/shell": "npm:^4.1.1" ci-info: "npm:^4.0.0" clipanion: "npm:^4.0.0-rc.2" @@ -5287,14 +5320,14 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/core": ^4.1.6 - checksum: 10/bd3f8748cc4f3b041f815b0fa5287c8c181a8d3a600a9b30694180bee6cf37fcede2296d46ff20d3ab04e837be33401824432c57712aa8367690c741b809826e + "@yarnpkg/core": ^4.2.0 + checksum: 10/8bfe4ea7165b0928bbc5542e520d7e638d66cbb21797269bb4eb1e7d136e2dad14495e9698ce89ffe5d5129debcd5bcc337bf0e5b1849f393c8127b2ad484708 languageName: node linkType: hard -"@yarnpkg/core@npm:^4.1.6": - version: 4.1.6 - resolution: "@yarnpkg/core@npm:4.1.6" +"@yarnpkg/core@npm:^4.1.6, @yarnpkg/core@npm:^4.2.0": + version: 4.2.0 + resolution: "@yarnpkg/core@npm:4.2.0" dependencies: "@arcanis/slice-ansi": "npm:^1.1.1" "@types/semver": "npm:^7.1.0" @@ -5322,7 +5355,7 @@ __metadata: treeify: "npm:^1.1.0" tslib: "npm:^2.4.0" tunnel: "npm:^0.0.6" - checksum: 10/6a766f3b91485ce210c898468ab51d97fcd49a3b19afd524c1adee031f46322311e559312f245c8ad32c853f6ace3b80665c08612876957dbce49f18fddbbba1 + checksum: 10/fd7f2093dd6a77759c116e79bde2ecd2142bfaa25aa6957c50e8fb42c105f299cf4f779acf4717cd5f95002aa335bbe36e8acd3fbfb573f455f76b5e0c9ec515 languageName: node linkType: hard @@ -5432,11 +5465,11 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-essentials@npm:^4.2.2": - version: 4.2.2 - resolution: "@yarnpkg/plugin-essentials@npm:4.2.2" +"@yarnpkg/plugin-essentials@npm:^4.3.0": + version: 4.3.0 + resolution: "@yarnpkg/plugin-essentials@npm:4.3.0" dependencies: - "@yarnpkg/fslib": "npm:^3.1.0" + "@yarnpkg/fslib": "npm:^3.1.1" "@yarnpkg/parsers": "npm:^3.0.2" ci-info: "npm:^4.0.0" clipanion: "npm:^4.0.0-rc.2" @@ -5447,10 +5480,10 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/cli": ^4.4.0 - "@yarnpkg/core": ^4.1.2 + "@yarnpkg/cli": ^4.6.0 + "@yarnpkg/core": ^4.2.0 "@yarnpkg/plugin-git": ^3.1.0 - checksum: 10/976a5c57fb5ba8446bdd9aad6b0b9b3a6e20699027c03df0190ce73e2fb4c77599ca16d8bc4ddf861c866abc853458e0e9cbd920e0b52e60953dd095cfa0394d + checksum: 10/52a5672dc47589d5b850b3c849e063b414289bf457bced7066eba8dc7962bfa024f17c775c0f432a5d1511e07b61a64244525fcb7647817138ad6fde25855f4d languageName: node linkType: hard @@ -5655,20 +5688,20 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-pnp@npm:^4.0.0, @yarnpkg/plugin-pnp@npm:^4.0.5": - version: 4.0.5 - resolution: "@yarnpkg/plugin-pnp@npm:4.0.5" +"@yarnpkg/plugin-pnp@npm:^4.0.0, @yarnpkg/plugin-pnp@npm:^4.0.5, @yarnpkg/plugin-pnp@npm:^4.0.6": + version: 4.0.6 + resolution: "@yarnpkg/plugin-pnp@npm:4.0.6" dependencies: - "@yarnpkg/fslib": "npm:^3.1.0" + "@yarnpkg/fslib": "npm:^3.1.1" "@yarnpkg/plugin-stage": "npm:^4.0.0" - "@yarnpkg/pnp": "npm:^4.0.5" + "@yarnpkg/pnp": "npm:^4.0.8" clipanion: "npm:^4.0.0-rc.2" micromatch: "npm:^4.0.2" tslib: "npm:^2.4.0" peerDependencies: - "@yarnpkg/cli": ^4.2.2 - "@yarnpkg/core": ^4.0.5 - checksum: 10/7d3277ffbb71ba8f6a1a647f4f66ff618c8645556784f3acf9fa198bbb2fad650043a8a927b7bc446f4748b1433a03219ea7030414b07417b3c31b8390631c0a + "@yarnpkg/cli": ^4.6.0 + "@yarnpkg/core": ^4.2.0 + checksum: 10/263b92aa005c929d31470484139cc28b42e86386da47e2a0303c8a45b2bdf7d1a2c72d881b9bd59659c725d6609523ad784ee175b4e8f987531802ebaf96f580 languageName: node linkType: hard @@ -5741,9 +5774,9 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-workspace-tools@npm:^4.1.1": - version: 4.1.1 - resolution: "@yarnpkg/plugin-workspace-tools@npm:4.1.1" +"@yarnpkg/plugin-workspace-tools@npm:^4.1.2": + version: 4.1.2 + resolution: "@yarnpkg/plugin-workspace-tools@npm:4.1.2" dependencies: "@yarnpkg/fslib": "npm:^3.1.1" clipanion: "npm:^4.0.0-rc.2" @@ -5752,20 +5785,20 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/cli": ^4.5.3 - "@yarnpkg/core": ^4.1.6 + "@yarnpkg/cli": ^4.6.0 + "@yarnpkg/core": ^4.2.0 "@yarnpkg/plugin-git": ^3.1.0 - checksum: 10/0011a6e3973b5b15029e074d4aa9caae7bd44d3a989b9cff3d9e6ae1d1a58cfd7c308dfbe0acef18e65c966233794a17275f996e5f5fbdc4f6115b2c1cb194fa + checksum: 10/f6f99728ad796c6bf0ce56d8a69dc2a93094ae787d03b67c8a32e981a4ad8803a2e906616089aa21ee686505aedf0f0b8d986bb2f40842470d8529ee9331ac7b languageName: node linkType: hard -"@yarnpkg/pnp@npm:^4.0.5, @yarnpkg/pnp@npm:^4.0.6, @yarnpkg/pnp@npm:^4.0.7": - version: 4.0.7 - resolution: "@yarnpkg/pnp@npm:4.0.7" +"@yarnpkg/pnp@npm:^4.0.6, @yarnpkg/pnp@npm:^4.0.7, @yarnpkg/pnp@npm:^4.0.8": + version: 4.0.8 + resolution: "@yarnpkg/pnp@npm:4.0.8" dependencies: "@types/node": "npm:^18.17.15" "@yarnpkg/fslib": "npm:^3.1.1" - checksum: 10/0a13983923b7cb5d3e6f70cb87deed07f3e71a57bcc46c51bf244bdad6c524002999bb02f2b4a0737d1747e72c7353b97b5ecc3626dda3580b97bfbb41506f32 + checksum: 10/1dcef20bdd92e539df84ebe58c513d2fe486bda490666ad6883a5f4bf2c2fd9f057aa906691f8e9271331e2734e73b0d299e4dc108a75f43a707efbbb3b918ae languageName: node linkType: hard @@ -5906,12 +5939,10 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: "npm:^4.3.4" - checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 10/3db6d8d4651f2aa1a9e4af35b96ab11a7607af57a24f3bc721a387eaa3b5f674e901f0a648b0caefd48f3fd117c7761b79a3b55854e2aebaa96c3f32cf76af84 languageName: node linkType: hard @@ -5984,9 +6015,9 @@ __metadata: linkType: hard "ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + version: 6.1.0 + resolution: "ansi-regex@npm:6.1.0" + checksum: 10/495834a53b0856c02acd40446f7130cb0f8284f4a39afdab20d5dc42b2e198b1196119fe887beed8f9055c4ff2055e3b2f6d4641d0be018cdfb64fedf6fc1aac languageName: node linkType: hard @@ -6108,15 +6139,6 @@ __metadata: languageName: node linkType: hard -"async-mutex@npm:^0.3.1": - version: 0.3.2 - resolution: "async-mutex@npm:0.3.2" - dependencies: - tslib: "npm:^2.3.1" - checksum: 10/cf0b02f7f916d202a727e15a64d51110c3258a719588ca263875024172aa9368efa5dbec6dc4f4fd10e35744e238e1075306a93ce86549de642d5f7d0c06bc23 - languageName: node - linkType: hard - "async-mutex@npm:^0.5.0": version: 0.5.0 resolution: "async-mutex@npm:0.5.0" @@ -6150,20 +6172,20 @@ __metadata: linkType: hard "axios@npm:^1.7.4": - version: 1.7.5 - resolution: "axios@npm:1.7.5" + version: 1.7.9 + resolution: "axios@npm:1.7.9" dependencies: follow-redirects: "npm:^1.15.6" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: 10/6cbcfe943a84089f420a900a3a3aeb54ee94dcc9c2b81b150434896357be5d1079eff0b1bbb628597371e79f896b1bc5776df04184756ba99656ff31df9a75bf + checksum: 10/b7a5f660ea53ba9c2a745bf5ad77ad8bf4f1338e13ccc3f9f09f810267d6c638c03dac88b55dae8dc98b79c57d2d6835be651d58d2af97c174f43d289a9fd007 languageName: node linkType: hard "b4a@npm:^1.6.4": - version: 1.6.6 - resolution: "b4a@npm:1.6.6" - checksum: 10/6154a36bd78b53ecd2843a829352532a1bf9fc8081dab339ba06ca3c9ffcf25d340c3b18fe4ba0fc17a546a54c1ed814cea92cd6b895f6bd2837ca4ee0fc9f52 + version: 1.6.7 + resolution: "b4a@npm:1.6.7" + checksum: 10/1ac056e3bce378d4d3e570e57319360a9d3125ab6916a1921b95bea33d9ee646698ebc75467561fd6fcc80ff697612124c89bb9b95e80db94c6dc23fcb977705 languageName: node linkType: hard @@ -6306,9 +6328,9 @@ __metadata: linkType: hard "bare-events@npm:^2.2.0": - version: 2.4.2 - resolution: "bare-events@npm:2.4.2" - checksum: 10/c1006ad13b7e62a412466d4eac8466b4ceb46ce84a5e2fc164cd4b10edaaa5016adc684147134b67a6a3865aaf5aa007191647bdb5dbf859b1d5735d2a9ddf3b + version: 2.5.4 + resolution: "bare-events@npm:2.5.4" + checksum: 10/135ef380b13f554ca2c6905bdbcfac8edae08fce85b7f953fa01f09a9f5b0da6a25e414111659bc9a6118216f0dd1f732016acd11ce91517f2afb26ebeb4b721 languageName: node linkType: hard @@ -6412,9 +6434,9 @@ __metadata: linkType: hard "bn.js@npm:^4.11.9": - version: 4.12.0 - resolution: "bn.js@npm:4.12.0" - checksum: 10/10f8db196d3da5adfc3207d35d0a42aa29033eb33685f20ba2c36cadfe2de63dad05df0a20ab5aae01b418d1c4b3d4d205273085262fa020d17e93ff32b67527 + version: 4.12.1 + resolution: "bn.js@npm:4.12.1" + checksum: 10/07f22df8880b423c4890648e95791319898b96712b6ebc5d6b1082b34074f09dedb8601e717d67f905ce29bb1a5313f9a2b1a2015a679e42c9eed94392c0d379 languageName: node linkType: hard @@ -6589,6 +6611,26 @@ __metadata: languageName: node linkType: hard +"cacache@npm:^19.0.1": + version: 19.0.1 + resolution: "cacache@npm:19.0.1" + dependencies: + "@npmcli/fs": "npm:^4.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^12.0.0" + tar: "npm:^7.4.3" + unique-filename: "npm:^4.0.0" + checksum: 10/ea026b27b13656330c2bbaa462a88181dcaa0435c1c2e705db89b31d9bdf7126049d6d0445ba746dca21454a0cfdf1d6f47fd39d34c8c8435296b30bc5738a13 + languageName: node + linkType: hard + "cacheable-lookup@npm:^5.0.3": version: 5.0.4 resolution: "cacheable-lookup@npm:5.0.4" @@ -6611,16 +6653,35 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.7": - version: 1.0.7 - resolution: "call-bind@npm:1.0.7" +"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1": + version: 1.0.1 + resolution: "call-bind-apply-helpers@npm:1.0.1" dependencies: - es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" function-bind: "npm:^1.1.2" + checksum: 10/6e30c621170e45f1fd6735e84d02ee8e02a3ab95cb109499d5308cbe5d1e84d0cd0e10b48cc43c76aa61450ae1b03a7f89c37c10fc0de8d4998b42aab0f268cc + languageName: node + linkType: hard + +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": + version: 1.0.8 + resolution: "call-bind@npm:1.0.8" + dependencies: + call-bind-apply-helpers: "npm:^1.0.0" + es-define-property: "npm:^1.0.0" get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.1" - checksum: 10/cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 + set-function-length: "npm:^1.2.2" + checksum: 10/659b03c79bbfccf0cde3a79e7d52570724d7290209823e1ca5088f94b52192dc1836b82a324d0144612f816abb2f1734447438e38d9dafe0b3f82c2a1b9e3bce + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3": + version: 1.0.3 + resolution: "call-bound@npm:1.0.3" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + get-intrinsic: "npm:^1.2.6" + checksum: 10/c39a8245f68cdb7c1f5eea7b3b1e3a7a90084ea6efebb78ebc454d698ade2c2bb42ec033abc35f1e596d62496b6100e9f4cdfad1956476c510130e2cda03266d languageName: node linkType: hard @@ -6653,9 +6714,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001690 - resolution: "caniuse-lite@npm:1.0.30001690" - checksum: 10/9fb4659eb09a298601b9593739072c481e2f5cc524bd0530e5e0f002e66246da5e866669854dfc0d53195ee36b201dab02f7933a7cdf60ccba7adb2d4a304caf + version: 1.0.30001692 + resolution: "caniuse-lite@npm:1.0.30001692" + checksum: 10/92449ec9e9ac6cd8ce7ecc18a8759ae34e4b3ef412acd998714ee9d70dc286bc8d0d6e4917fa454798da9b37667eb5b3b41386bc9d25e4274d0b9c7af8339b0e languageName: node linkType: hard @@ -6687,9 +6748,9 @@ __metadata: linkType: hard "chalk@npm:^5.3.0": - version: 5.3.0 - resolution: "chalk@npm:5.3.0" - checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea + version: 5.4.1 + resolution: "chalk@npm:5.4.1" + checksum: 10/29df3ffcdf25656fed6e95962e2ef86d14dfe03cd50e7074b06bad9ffbbf6089adbb40f75c00744d843685c8d008adaf3aed31476780312553caf07fa86e5bc7 languageName: node linkType: hard @@ -6707,6 +6768,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10/b63cb1f73d171d140a2ed8154ee6566c8ab775d3196b0e03a2a94b5f6a0ce7777ee5685ca56849403c8d17bd457a6540672f9a60696a6137c7a409097495b82c + languageName: node + linkType: hard + "ci-info@npm:^2.0.0": version: 2.0.0 resolution: "ci-info@npm:2.0.0" @@ -6729,19 +6797,19 @@ __metadata: linkType: hard "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.4 - resolution: "cipher-base@npm:1.0.4" + version: 1.0.6 + resolution: "cipher-base@npm:1.0.6" dependencies: - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - checksum: 10/3d5d6652ca499c3f7c5d7fdc2932a357ec1e5aa84f2ad766d850efd42e89753c97b795c3a104a8e7ae35b4e293f5363926913de3bf8181af37067d9d541ca0db + inherits: "npm:^2.0.4" + safe-buffer: "npm:^5.2.1" + checksum: 10/faf232deff2351448ea23d265eb8723e035ebbb454baca45fb60c1bd71056ede8b153bef1b221e067f13e6b9288ebb83bb6ae2d5dd4cec285411f9fc22ec1f5b languageName: node linkType: hard "cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.3.1": - version: 1.4.0 - resolution: "cjs-module-lexer@npm:1.4.0" - checksum: 10/b041096749792526120d8b8756929f8ef5dd4596502a0e1013f857e3027acd6091915fea77037921d70ee1a99988a100d994d3d3c2e323b04dd4c5ffd516cf13 + version: 1.4.1 + resolution: "cjs-module-lexer@npm:1.4.1" + checksum: 10/6e830a1e00a34d416949bbc1924f3e8da65cef4a6a09e2b7fa35722e2d1c34bf378d3baca987b698d1cbc3eb83e44b044039b4e82755c96f30e0f03d1d227637 languageName: node linkType: hard @@ -6944,30 +7012,30 @@ __metadata: linkType: hard "contentful-resolve-response@npm:^1.9.0": - version: 1.9.0 - resolution: "contentful-resolve-response@npm:1.9.0" + version: 1.9.2 + resolution: "contentful-resolve-response@npm:1.9.2" dependencies: fast-copy: "npm:^2.1.7" - checksum: 10/0c5daa59a3a6b020f9b5316812e3f14e62833b4aead008527c5bfde6549365e8e8e9f373af8836f06ca7b2023d861fdd2c241d3e74d3797133d18983be8bb3b3 + checksum: 10/7fce57e33d5f874c65683567af30d1f1c32a8769558479f61b4d465201f8ea979a52b9b31f33d01a5437477aa0195a00565792efba345f2b21689e13519d70b3 languageName: node linkType: hard "contentful-sdk-core@npm:^8.3.1": - version: 8.3.1 - resolution: "contentful-sdk-core@npm:8.3.1" + version: 8.3.2 + resolution: "contentful-sdk-core@npm:8.3.2" dependencies: fast-copy: "npm:^2.1.7" lodash.isplainobject: "npm:^4.0.6" lodash.isstring: "npm:^4.0.1" p-throttle: "npm:^4.1.1" qs: "npm:^6.11.2" - checksum: 10/645d3a5d296d0e2a5ce87cceb04cf1ddf572183b5946cb1b3b717436bc7be96864216225fb845e61850d580436021c6284e7c95da0600a16c89c0af81a5f0d2c + checksum: 10/4af0aba2bb7e3db3ebf260fea74843de89f150f5af883134c370eb695fd8b2587cf94d4524d03020286f565eb3bff7b12d42f2a38718b62eb75cb28556e40f42 languageName: node linkType: hard "contentful@npm:^10.15.0": - version: 10.15.0 - resolution: "contentful@npm:10.15.0" + version: 10.15.1 + resolution: "contentful@npm:10.15.1" dependencies: "@contentful/content-source-maps": "npm:^0.11.0" "@contentful/rich-text-types": "npm:^16.0.2" @@ -6976,7 +7044,7 @@ __metadata: contentful-sdk-core: "npm:^8.3.1" json-stringify-safe: "npm:^5.0.1" type-fest: "npm:^4.0.0" - checksum: 10/b57c51faa99074a2f60c930c4827d1f8fe9867a359e53738532bbe859f5d72e750645fa4e195e65ad015811f344d95a0b3cebe6debef7d4e92ce9510bd55939e + checksum: 10/eb913a79e38d87bc7fb3a79952e4d7c5a1de5cccfbe0a012e8131c9c1e5a0a525cfcb7eaea971b02fb9e57b9e49c71ce96dd7096c3f65483992017ef70de80e5 languageName: node linkType: hard @@ -7338,15 +7406,6 @@ __metadata: languageName: node linkType: hard -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: "npm:^4.0.0" - checksum: 10/fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 - languageName: node - linkType: hard - "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -7372,23 +7431,34 @@ __metadata: languageName: node linkType: hard -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10/5add88a3d68d42d6e6130a0cac450b7c2edbe73364bbd2fc334564418569bea97c6943a8fcd70e27130bf32afc236f30982fc4905039b703f23e9e0433c29934 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 languageName: node linkType: hard "electron-to-chromium@npm:^1.5.73": - version: 1.5.79 - resolution: "electron-to-chromium@npm:1.5.79" - checksum: 10/c5b25ba04b4f4b46c4024b96e00e43adcd6c321b48c74c8d2660f69704901da5a6592009cbf96c36c89e3f6b53d7742e2b89514477fddbccf4e5c4caebed9d49 + version: 1.5.82 + resolution: "electron-to-chromium@npm:1.5.82" + checksum: 10/2c8e01d71515773d6789013162505a31b831c4f4e7b4a1e9fc65ed6d7e31e21f71b0880dd141eadbb93d89e2a2fce9636ac72604c28fa0960d44e8dacbed431e languageName: node linkType: hard "elliptic@npm:^6.5.7": - version: 6.5.7 - resolution: "elliptic@npm:6.5.7" + version: 6.6.1 + resolution: "elliptic@npm:6.6.1" dependencies: bn.js: "npm:^4.11.9" brorand: "npm:^1.1.0" @@ -7397,7 +7467,7 @@ __metadata: inherits: "npm:^2.0.4" minimalistic-assert: "npm:^1.0.1" minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/fbad1fad0a5cc07df83f80cc1f7a784247ef59075194d3e340eaeb2f4dd594825ee24c7e9b0cf279c9f1982efe610503bb3139737926428c4821d4fca1bcf348 + checksum: 10/dc678c9febd89a219c4008ba3a9abb82237be853d9fd171cd602c8fb5ec39927e65c6b5e7a1b2a4ea82ee8e0ded72275e7932bb2da04a5790c2638b818e4e1c5 languageName: node linkType: hard @@ -7490,12 +7560,10 @@ __metadata: languageName: node linkType: hard -"es-define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "es-define-property@npm:1.0.0" - dependencies: - get-intrinsic: "npm:^1.2.4" - checksum: 10/f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 +"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10/f8dc9e660d90919f11084db0a893128f3592b781ce967e4fccfb8f3106cb83e400a4032c559184ec52ee1dbd4b01e7776c7cd0b3327b1961b1a4a7008920fe78 languageName: node linkType: hard @@ -7513,6 +7581,15 @@ __metadata: languageName: node linkType: hard +"es-object-atoms@npm:^1.0.0": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10/54fe77de288451dae51c37bfbfe3ec86732dc3778f98f3eb3bdb4bf48063b2c0b8f9c93542656986149d08aa5be3204286e2276053d19582b76753f1a2728867 + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -7654,8 +7731,8 @@ __metadata: linkType: hard "eslint-plugin-jest@npm:^28.8.3": - version: 28.10.0 - resolution: "eslint-plugin-jest@npm:28.10.0" + version: 28.11.0 + resolution: "eslint-plugin-jest@npm:28.11.0" dependencies: "@typescript-eslint/utils": "npm:^6.0.0 || ^7.0.0 || ^8.0.0" peerDependencies: @@ -7667,7 +7744,7 @@ __metadata: optional: true jest: optional: true - checksum: 10/cb19f2171e93873d9207425c4fa52ec49018579d73ece23a1ffea90f3ffd284b0e48f74ff4f50b15ff31882b06b03fec0e48c9c6ca830acdeff8931802ef0a9e + checksum: 10/7f3896ec2dc03110688bb9f359a7aa1ba1a6d9a60ffbc3642361c4aaf55afcba9ce36b6609b20b1507028c2170ffe29b0f3e9cc9b7fe12fdd233740a2f9ce0a1 languageName: node linkType: hard @@ -7711,8 +7788,8 @@ __metadata: linkType: hard "eslint-plugin-prettier@npm:^5.2.1": - version: 5.2.1 - resolution: "eslint-plugin-prettier@npm:5.2.1" + version: 5.2.2 + resolution: "eslint-plugin-prettier@npm:5.2.2" dependencies: prettier-linter-helpers: "npm:^1.0.0" synckit: "npm:^0.9.1" @@ -7726,7 +7803,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 10/10ddf68215237e327af09a47adab4c63f3885fda4fb28c4c42d1fc5f47d8a0cc45df6484799360ff1417a0aa3c77c3aaac49d7e9dfd145557b17e2d7ecc2a27c + checksum: 10/292569865fde6a91646037f58105c18225f5cd57e255966f8388b13c196ce023f84e22100408dcd30472c02d0846a897b8afe460ece57dfc23e80e6cac70a644 languageName: node linkType: hard @@ -7766,16 +7843,16 @@ __metadata: linkType: hard "eslint@npm:^9.11.0": - version: 9.17.0 - resolution: "eslint@npm:9.17.0" + version: 9.18.0 + resolution: "eslint@npm:9.18.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" "@eslint/config-array": "npm:^0.19.0" - "@eslint/core": "npm:^0.9.0" + "@eslint/core": "npm:^0.10.0" "@eslint/eslintrc": "npm:^3.2.0" - "@eslint/js": "npm:9.17.0" - "@eslint/plugin-kit": "npm:^0.2.3" + "@eslint/js": "npm:9.18.0" + "@eslint/plugin-kit": "npm:^0.2.5" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.1" @@ -7810,7 +7887,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/a48ee67dd4e737974bbb49ca5d12d0ce35bcd874507807599e3655bb398320ab27c9deed1aad508a963967815e626c21208f52158c2fc0796d0cc8186528efeb + checksum: 10/85f22991aab4b0809fdfc557ec2bd309062e7211b631674e71827a73c45e44febaa80dedda35150154e331a2d372c3a25e8e5dd4a99dc8a982fe8f7d645d859f languageName: node linkType: hard @@ -7961,17 +8038,17 @@ __metadata: linkType: hard "ethers@npm:^6.12.0": - version: 6.13.2 - resolution: "ethers@npm:6.13.2" + version: 6.13.5 + resolution: "ethers@npm:6.13.5" dependencies: "@adraffy/ens-normalize": "npm:1.10.1" "@noble/curves": "npm:1.2.0" "@noble/hashes": "npm:1.3.2" - "@types/node": "npm:18.15.13" + "@types/node": "npm:22.7.5" aes-js: "npm:4.0.0-beta.5" - tslib: "npm:2.4.0" + tslib: "npm:2.7.0" ws: "npm:8.17.1" - checksum: 10/e611c2e2c5340982dfd1f004895f55abda11748a7edec9e6315226dec42d58aa61b827dd389ec904db5f9a244c475ae795e528da579251fdf62e914bde12809e + checksum: 10/ccba21a83679fb6a7c3eb9d187593501565d140064f2db28057a64d6707678bacf2adf4555882c4814688246da73173560df81fd3361fd2f227b5d3c75cb8685 languageName: node linkType: hard @@ -8149,7 +8226,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.2, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.2": +"fast-glob@npm:^3.2.2, fast-glob@npm:^3.3.2": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -8191,13 +8268,13 @@ __metadata: linkType: hard "fast-xml-parser@npm:^4.4.1": - version: 4.4.1 - resolution: "fast-xml-parser@npm:4.4.1" + version: 4.5.1 + resolution: "fast-xml-parser@npm:4.5.1" dependencies: strnum: "npm:^1.0.5" bin: fxparser: src/cli/cli.js - checksum: 10/0c05ab8703630d8c857fafadbd78d0020d3a8e54310c3842179cd4a0d9d97e96d209ce885e91241f4aa9dd8dfc2fd924a682741a423d65153cad34da2032ec44 + checksum: 10/17ce5908e798de1b6d12a39d26f04ac3b582ea9ce28f3a6e3b9c401edcb74790f28df84d75377608af53308ff8caad2b244ba1283cc4b5b4cf4cc7bd532a9983 languageName: node linkType: hard @@ -8209,11 +8286,11 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.17.1 - resolution: "fastq@npm:1.17.1" + version: 1.18.0 + resolution: "fastq@npm:1.18.0" dependencies: reusify: "npm:^1.0.4" - checksum: 10/a443180068b527dd7b3a63dc7f2a47ceca2f3e97b9c00a1efe5538757e6cc4056a3526df94308075d7727561baf09ebaa5b67da8dcbddb913a021c5ae69d1f69 + checksum: 10/c5b501333dc8f5d188d828ea162aad03ff5a81aed185b6d4a5078aaeae0a42babc34296d7af13ebce86401cccd93c9b7b3cbf61280821c5f20af233378b42fbb languageName: node linkType: hard @@ -8235,6 +8312,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.4.2": + version: 6.4.2 + resolution: "fdir@npm:6.4.2" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10/5ff80d1d2034e75cc68be175401c9f64c4938a6b2c1e9a0c27f2d211ffbe491fd86d29e4576825d9da8aff9bd465f0283427c2dddc11653457906c46d3bbc448 + languageName: node + linkType: hard + "figgy-pudding@npm:^3.5.1": version: 3.5.2 resolution: "figgy-pudding@npm:3.5.2" @@ -8293,37 +8382,38 @@ __metadata: linkType: hard "firebase@npm:^10.11.0": - version: 10.13.0 - resolution: "firebase@npm:10.13.0" - dependencies: - "@firebase/analytics": "npm:0.10.7" - "@firebase/analytics-compat": "npm:0.2.13" - "@firebase/app": "npm:0.10.9" - "@firebase/app-check": "npm:0.8.7" - "@firebase/app-check-compat": "npm:0.3.14" - "@firebase/app-compat": "npm:0.2.39" + version: 10.14.1 + resolution: "firebase@npm:10.14.1" + dependencies: + "@firebase/analytics": "npm:0.10.8" + "@firebase/analytics-compat": "npm:0.2.14" + "@firebase/app": "npm:0.10.13" + "@firebase/app-check": "npm:0.8.8" + "@firebase/app-check-compat": "npm:0.3.15" + "@firebase/app-compat": "npm:0.2.43" "@firebase/app-types": "npm:0.9.2" - "@firebase/auth": "npm:1.7.7" - "@firebase/auth-compat": "npm:0.5.12" - "@firebase/database": "npm:1.0.7" - "@firebase/database-compat": "npm:1.0.7" - "@firebase/firestore": "npm:4.7.0" - "@firebase/firestore-compat": "npm:0.3.35" - "@firebase/functions": "npm:0.11.6" - "@firebase/functions-compat": "npm:0.3.12" - "@firebase/installations": "npm:0.6.8" - "@firebase/installations-compat": "npm:0.2.8" - "@firebase/messaging": "npm:0.12.10" - "@firebase/messaging-compat": "npm:0.2.10" - "@firebase/performance": "npm:0.6.8" - "@firebase/performance-compat": "npm:0.2.8" - "@firebase/remote-config": "npm:0.4.8" - "@firebase/remote-config-compat": "npm:0.2.8" - "@firebase/storage": "npm:0.13.0" - "@firebase/storage-compat": "npm:0.3.10" - "@firebase/util": "npm:1.9.7" - "@firebase/vertexai-preview": "npm:0.0.3" - checksum: 10/dd4d62acb3146cb96f88a98eead8a5a02ef42dc5f5a918bbf496f2f894a048ff9aef64b79f2dc8909995b7d3ad2d4d36d6a72add7c8ef3ee46cb811641fc572a + "@firebase/auth": "npm:1.7.9" + "@firebase/auth-compat": "npm:0.5.14" + "@firebase/data-connect": "npm:0.1.0" + "@firebase/database": "npm:1.0.8" + "@firebase/database-compat": "npm:1.0.8" + "@firebase/firestore": "npm:4.7.3" + "@firebase/firestore-compat": "npm:0.3.38" + "@firebase/functions": "npm:0.11.8" + "@firebase/functions-compat": "npm:0.3.14" + "@firebase/installations": "npm:0.6.9" + "@firebase/installations-compat": "npm:0.2.9" + "@firebase/messaging": "npm:0.12.12" + "@firebase/messaging-compat": "npm:0.2.12" + "@firebase/performance": "npm:0.6.9" + "@firebase/performance-compat": "npm:0.2.9" + "@firebase/remote-config": "npm:0.4.9" + "@firebase/remote-config-compat": "npm:0.2.9" + "@firebase/storage": "npm:0.13.2" + "@firebase/storage-compat": "npm:0.3.12" + "@firebase/util": "npm:1.10.0" + "@firebase/vertexai-preview": "npm:0.0.4" + checksum: 10/1b2fd7b653f632d2bb0cf3b87e7eda0ae69d28b702a7de00d2a166c7985b8747ef9d15f7ac151847d242f91a1cb08c689d0a07197e8b80561ff1a679398bf9f8 languageName: node linkType: hard @@ -8338,19 +8428,19 @@ __metadata: linkType: hard "flatted@npm:^3.2.9": - version: 3.3.1 - resolution: "flatted@npm:3.3.1" - checksum: 10/7b8376061d5be6e0d3658bbab8bde587647f68797cf6bfeae9dea0e5137d9f27547ab92aaff3512dd9d1299086a6d61be98e9d48a56d17531b634f77faadbc49 + version: 3.3.2 + resolution: "flatted@npm:3.3.2" + checksum: 10/ac3c159742e01d0e860a861164bcfd35bb567ccbebb8a0dd041e61cf3c64a435b917dd1e7ed1c380c2ebca85735fb16644485ec33665bc6aafc3b316aa1eed44 languageName: node linkType: hard "follow-redirects@npm:^1.15.6": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" + version: 1.15.9 + resolution: "follow-redirects@npm:1.15.9" peerDependenciesMeta: debug: optional: true - checksum: 10/70c7612c4cab18e546e36b991bbf8009a1a41cf85354afe04b113d1117569abf760269409cb3eb842d9f7b03d62826687086b081c566ea7b1e6613cf29030bf7 + checksum: 10/e3ab42d1097e90d28b913903841e6779eb969b62a64706a3eb983e894a5db000fbd89296f45f08885a0e54cd558ef62e81be1165da9be25a6c44920da10f424c languageName: node linkType: hard @@ -8381,24 +8471,24 @@ __metadata: linkType: hard "form-data@npm:^3.0.0": - version: 3.0.1 - resolution: "form-data@npm:3.0.1" + version: 3.0.2 + resolution: "form-data@npm:3.0.2" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 10/944b40ff63b9cb1ca7a97e70f72104c548e0b0263e3e817e49919015a0d687453086259b93005389896dbffd3777cccea2e67c51f4e827590e5979b14ff91bf7 + checksum: 10/b8d71d7149de5881c6c8ac75c03ac2e809b1b729399320cc41f59a63043fa34b95dfef5259212d6d902abb4916af48a7ca60ad5c035806ba8e3c7843dbaf3057 languageName: node linkType: hard "form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" + version: 4.0.1 + resolution: "form-data@npm:4.0.1" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 10/7264aa760a8cf09482816d8300f1b6e2423de1b02bba612a136857413fdc96d7178298ced106817655facc6b89036c6e12ae31c9eb5bdc16aabf502ae8a5d805 + checksum: 10/6adb1cff557328bc6eb8a68da205f9ae44ab0e88d4d9237aaf91eed591ffc64f77411efb9016af7d87f23d0a038c45a788aa1c6634e51175c4efa36c2bc53774 languageName: node linkType: hard @@ -8485,16 +8575,21 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.4": - version: 1.2.4 - resolution: "get-intrinsic@npm:1.2.4" +"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6": + version: 1.2.7 + resolution: "get-intrinsic@npm:1.2.7" dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" function-bind: "npm:^1.1.2" - has-proto: "npm:^1.0.1" - has-symbols: "npm:^1.0.3" - hasown: "npm:^2.0.0" - checksum: 10/85bbf4b234c3940edf8a41f4ecbd4e25ce78e5e6ad4e24ca2f77037d983b9ef943fd72f00f3ee97a49ec622a506b67db49c36246150377efcda1c9eb03e5f06d + get-proto: "npm:^1.0.0" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10/4f7149c9a826723f94c6d49f70bcb3df1d3f9213994fab3668f12f09fa72074681460fb29ebb6f135556ec6372992d63802386098791a8f09cfa6f27090fa67b languageName: node linkType: hard @@ -8512,6 +8607,16 @@ __metadata: languageName: node linkType: hard +"get-proto@npm:^1.0.0": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/4fc96afdb58ced9a67558698b91433e6b037aaa6f1493af77498d7c85b141382cf223c0e5946f334fb328ee85dfe6edd06d218eaf09556f4bc4ec6005d7f5f7b + languageName: node + linkType: hard + "get-stdin@npm:^9.0.0": version: 9.0.0 resolution: "get-stdin@npm:9.0.0" @@ -8677,19 +8782,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.2": - version: 13.2.2 - resolution: "globby@npm:13.2.2" - dependencies: - dir-glob: "npm:^3.0.1" - fast-glob: "npm:^3.3.0" - ignore: "npm:^5.2.4" - merge2: "npm:^1.4.1" - slash: "npm:^4.0.0" - checksum: 10/4494a9d2162a7e4d327988b26be66d8eab87d7f59a83219e74b065e2c3ced23698f68fb10482bf9337133819281803fb886d6ae06afbb2affa743623eb0b1949 - languageName: node - linkType: hard - "globrex@npm:^0.1.2": version: 0.1.2 resolution: "globrex@npm:0.1.2" @@ -8697,12 +8789,10 @@ __metadata: languageName: node linkType: hard -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.1.3" - checksum: 10/5fbc7ad57b368ae4cd2f41214bd947b045c1a4be2f194a7be1778d71f8af9dbf4004221f3b6f23e30820eb0d052b4f819fe6ebe8221e2a3c6f0ee4ef173421ca +"gopd@npm:^1.0.1, gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10/94e296d69f92dc1c0768fcfeecfb3855582ab59a7c75e969d5f96ce50c3d201fd86d5a2857c22565764d5bb8a816c7b1e58f133ec318cd56274da36c5e3fb1a1 languageName: node linkType: hard @@ -8762,21 +8852,14 @@ __metadata: languageName: node linkType: hard -"has-proto@npm:^1.0.1": - version: 1.0.3 - resolution: "has-proto@npm:1.0.3" - checksum: 10/0b67c2c94e3bea37db3e412e3c41f79d59259875e636ba471e94c009cdfb1fa82bf045deeffafc7dbb9c148e36cae6b467055aaa5d9fad4316e11b41e3ba551a - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: 10/464f97a8202a7690dadd026e6d73b1ceeddd60fe6acfd06151106f050303eaa75855aaa94969df8015c11ff7c505f196114d22f7386b4a471038da5874cf5e9b +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10/959385c98696ebbca51e7534e0dc723ada325efa3475350951363cce216d27373e0259b63edb599f72eb94d6cde8577b4b2375f080b303947e560f85692834fa languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": +"has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" dependencies: @@ -8806,7 +8889,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0, hasown@npm:^2.0.2": +"hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -8880,9 +8963,9 @@ __metadata: linkType: hard "http-parser-js@npm:>=0.5.1": - version: 0.5.8 - resolution: "http-parser-js@npm:0.5.8" - checksum: 10/2a78a567ee6366dae0129d819b799dce1f95ec9732c5ab164a78ee69804ffb984abfa0660274e94e890fc54af93546eb9f12b6d10edbaed017e2d41c29b7cf29 + version: 0.5.9 + resolution: "http-parser-js@npm:0.5.9" + checksum: 10/65e6ef5e063b4f67c590bdd122b255e9b70c5bf3429718f8b72951fe98f4f968c55a58ec88cc96a11357a437d75c4af9302b8026c0b53c525065ff4eb0cd969e languageName: node linkType: hard @@ -8928,12 +9011,12 @@ __metadata: linkType: hard "https-proxy-agent@npm:^7.0.1": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" dependencies: - agent-base: "npm:^7.0.2" + agent-base: "npm:^7.1.2" debug: "npm:4" - checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab + checksum: 10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13 languageName: node linkType: hard @@ -9134,12 +9217,12 @@ __metadata: linkType: hard "is-arguments@npm:^1.0.4": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" + version: 1.2.0 + resolution: "is-arguments@npm:1.2.0" dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10/a170c7e26082e10de9be6e96d32ae3db4d5906194051b792e85fae3393b53cf2cb5b3557863e5c8ccbab55e2fd8f2f75aa643d437613f72052cf0356615c34be + call-bound: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.2" + checksum: 10/471a8ef631b8ee8829c43a8ab05c081700c0e25180c73d19f3bf819c1a8448c426a9e8e601f278973eca68966384b16ceb78b8c63af795b099cd199ea5afc457 languageName: node linkType: hard @@ -9177,12 +9260,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.12.0, is-core-module@npm:^2.13.0": - version: 2.15.1 - resolution: "is-core-module@npm:2.15.1" +"is-core-module@npm:^2.12.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0": + version: 2.16.1 + resolution: "is-core-module@npm:2.16.1" dependencies: hasown: "npm:^2.0.2" - checksum: 10/77316d5891d5743854bcef2cd2f24c5458fb69fbc9705c12ca17d54a2017a67d0693bbf1ba8c77af376c0eef6bf6d1b27a4ab08e4db4e69914c3789bdf2ceec5 + checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb languageName: node linkType: hard @@ -9215,11 +9298,14 @@ __metadata: linkType: hard "is-generator-function@npm:^1.0.7": - version: 1.0.10 - resolution: "is-generator-function@npm:1.0.10" + version: 1.1.0 + resolution: "is-generator-function@npm:1.1.0" dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10/499a3ce6361064c3bd27fbff5c8000212d48506ebe1977842bbd7b3e708832d0deb1f4cc69186ece3640770e8c4f1287b24d99588a0b8058b2dbdd344bc1f47f + call-bound: "npm:^1.0.3" + get-proto: "npm:^1.0.0" + has-tostringtag: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10/5906ff51a856a5fbc6b90a90fce32040b0a6870da905f98818f1350f9acadfc9884f7c3dec833fce04b83dd883937b86a190b6593ede82e8b1af8b6c4ecf7cbd languageName: node linkType: hard @@ -9277,6 +9363,18 @@ __metadata: languageName: node linkType: hard +"is-regex@npm:^1.2.1": + version: 1.2.1 + resolution: "is-regex@npm:1.2.1" + dependencies: + call-bound: "npm:^1.0.2" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10/c42b7efc5868a5c9a4d8e6d3e9816e8815c611b09535c00fead18a1138455c5cb5e1887f0023a467ad3f9c419d62ba4dc3d9ba8bafe55053914d6d6454a945d2 + languageName: node + linkType: hard + "is-ssh@npm:^1.4.0": version: 1.4.0 resolution: "is-ssh@npm:1.4.0" @@ -9301,11 +9399,11 @@ __metadata: linkType: hard "is-typed-array@npm:^1.1.3": - version: 1.1.13 - resolution: "is-typed-array@npm:1.1.13" + version: 1.1.15 + resolution: "is-typed-array@npm:1.1.15" dependencies: - which-typed-array: "npm:^1.1.14" - checksum: 10/f850ba08286358b9a11aee6d93d371a45e3c59b5953549ee1c1a9a55ba5c1dd1bd9952488ae194ad8f32a9cf5e79c8fa5f0cc4d78c00720aa0bbcf238b38062d + which-typed-array: "npm:^1.1.16" + checksum: 10/e8cf60b9ea85667097a6ad68c209c9722cfe8c8edf04d6218366469e51944c5cc25bae45ffb845c23f811d262e4314d3b0168748eb16711aa34d12724cdf0735 languageName: node linkType: hard @@ -10016,11 +10114,11 @@ __metadata: linkType: hard "jest-when@npm:^3.4.2": - version: 3.6.0 - resolution: "jest-when@npm:3.6.0" + version: 3.7.0 + resolution: "jest-when@npm:3.7.0" peerDependencies: jest: ">= 25" - checksum: 10/0cb92738ccfa5711a685107f4437f18aefbe3cda120c912a9d49b612eeef03a910481ab40fe753fd42c4e617ffbb3d84c6bd66a76d963dac7f1ad9e9e5059359 + checksum: 10/b5b88d077ed467aab220c71c885dbc5f448604f06e68f761ce9f479c99bb74e0dbf553d1cc980751d88401b034a578e1c44eec5e4095743b7586f02bb7c6313d languageName: node linkType: hard @@ -10281,9 +10379,9 @@ __metadata: linkType: hard "jsonschema@npm:^1.4.1": - version: 1.4.1 - resolution: "jsonschema@npm:1.4.1" - checksum: 10/d7a188da7a3100a2caa362b80e98666d46607b7a7153aac405b8e758132961911c6df02d444d4700691330874e21a62639f550e856b21ddd28423690751ca9c6 + version: 1.5.0 + resolution: "jsonschema@npm:1.5.0" + checksum: 10/46bf49b388ba922073bcb3c8d5e90af9d29fc8303dc866fd440182c88d6b4fd2807679fd39cdefb4113156d104ea47da9c0ff4bbcb0032c9fa29461cb1a92182 languageName: node linkType: hard @@ -10421,16 +10519,16 @@ __metadata: linkType: hard "loglevel@npm:^1.8.1": - version: 1.9.1 - resolution: "loglevel@npm:1.9.1" - checksum: 10/863cbbcddf850a937482c604e2d11586574a5110b746bb49c7cc04739e01f6035f6db841d25377106dd330bca7142d74995f15a97c5f3ea0af86d9472d4a99f4 + version: 1.9.2 + resolution: "loglevel@npm:1.9.2" + checksum: 10/6153d8db308323f7ee20130bc40309e7a976c30a10379d8666b596d9c6441965c3e074c8d7ee3347fe5cfc059c0375b6f3e8a10b93d5b813cc5547f5aa412a29 languageName: node linkType: hard "long@npm:^5.0.0": - version: 5.2.3 - resolution: "long@npm:5.2.3" - checksum: 10/9167ec6947a825b827c30da169a7384eec6c0c9ec2f0b9c74da2e93d81159bbe39fb09c3f13dae9721d4b807ccfa09797a7dd1012f5d478e3e33ca3c78b608e6 + version: 5.2.4 + resolution: "long@npm:5.2.4" + checksum: 10/c27c060a683d4d76dc48da12ded0ae49c610aaf10d028ec938829d7bebe916979dcc8b67ed71f8bf6d845a90151b66a9b741a3ee51ec874908e496c2a576697a languageName: node linkType: hard @@ -10475,19 +10573,19 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.2.1": +"luxon@npm:^3.2.1, luxon@npm:^3.5.0": version: 3.5.0 resolution: "luxon@npm:3.5.0" checksum: 10/48f86e6c1c96815139f8559456a3354a276ba79bcef0ae0d4f2172f7652f3ba2be2237b0e103b8ea0b79b47715354ac9fac04eb1db3485dcc72d5110491dd47f languageName: node linkType: hard -"magic-string@npm:^0.30.10": - version: 0.30.11 - resolution: "magic-string@npm:0.30.11" +"magic-string@npm:^0.30.11": + version: 0.30.17 + resolution: "magic-string@npm:0.30.17" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.5.0" - checksum: 10/b784d2240252f5b1e755d487354ada4c672cbca16f045144f7185a75b059210e5fcca7be7be03ef1bac2ca754c4428b21d36ae64a9057ba429916f06b8c54eb2 + checksum: 10/2f71af2b0afd78c2e9012a29b066d2c8ba45a9cd0c8070f7fd72de982fb1c403b4e3afdb1dae00691d56885ede66b772ef6bedf765e02e3a7066208fe2fec4aa languageName: node linkType: hard @@ -10527,6 +10625,25 @@ __metadata: languageName: node linkType: hard +"make-fetch-happen@npm:^14.0.3": + version: 14.0.3 + resolution: "make-fetch-happen@npm:14.0.3" + dependencies: + "@npmcli/agent": "npm:^3.0.0" + cacache: "npm:^19.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^4.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^5.0.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^12.0.0" + checksum: 10/fce0385840b6d86b735053dfe941edc2dd6468fda80fe74da1eeff10cbd82a75760f406194f2bc2fa85b99545b2bc1f84c08ddf994b21830775ba2d1a87e8bdf + languageName: node + linkType: hard + "makeerror@npm:1.0.12": version: 1.0.12 resolution: "makeerror@npm:1.0.12" @@ -10554,6 +10671,13 @@ __metadata: languageName: node linkType: hard +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10/11df2eda46d092a6035479632e1ec865b8134bdfc4bd9e571a656f4191525404f13a283a515938c3a8de934dbfd9c09674d9da9fa831e6eb7e22b50b197d2edd + languageName: node + linkType: hard + "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -10572,7 +10696,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": +"merge2@npm:^1.3.0": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 10/7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -10705,6 +10829,21 @@ __metadata: languageName: node linkType: hard +"minipass-fetch@npm:^4.0.0": + version: 4.0.0 + resolution: "minipass-fetch@npm:4.0.0" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^3.0.1" + dependenciesMeta: + encoding: + optional: true + checksum: 10/4b0772dbee77727b469dc5bfc371541d9aba1e243fbb46ddc1b9ff7efa4de4a4cf5ff3a359d6a3b3a460ca26df9ae67a9c93be26ab6417c225e49d63b52b2801 + languageName: node + linkType: hard + "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -10748,7 +10887,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 @@ -10765,6 +10904,16 @@ __metadata: languageName: node linkType: hard +"minizlib@npm:^3.0.1": + version: 3.0.1 + resolution: "minizlib@npm:3.0.1" + dependencies: + minipass: "npm:^7.0.4" + rimraf: "npm:^5.0.5" + checksum: 10/622cb85f51e5c206a080a62d20db0d7b4066f308cb6ce82a9644da112367c3416ae7062017e631eb7ac8588191cfa4a9a279b8651c399265202b298e98c4acef + languageName: node + linkType: hard + "mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" @@ -10774,6 +10923,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^3.0.1": + version: 3.0.1 + resolution: "mkdirp@npm:3.0.1" + bin: + mkdirp: dist/cjs/src/bin.js + checksum: 10/16fd79c28645759505914561e249b9a1f5fe3362279ad95487a4501e4467abeb714fd35b95307326b8fd03f3c7719065ef11a6f97b7285d7888306d1bd2232ba + languageName: node + linkType: hard + "ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -10782,9 +10940,9 @@ __metadata: linkType: hard "multiformats@npm:^13.1.0": - version: 13.2.2 - resolution: "multiformats@npm:13.2.2" - checksum: 10/6e673320e9b06d5fdbbf2bde0d3132f13fac94fb40f36d646265b5c38eba4a28c40a2c76b4efa0c1a23517fe87320e540e9ef7f28d71c1cc3239c91bf6770ce6 + version: 13.3.1 + resolution: "multiformats@npm:13.3.1" + checksum: 10/2e529613d457590dffe212a658546f313c7c7296d240d952d2baee7ce0abb227116d784f05cf4d238ef0db7d72ad2c3d04ea3c6b9bfd20db805a092024ce8d7e languageName: node linkType: hard @@ -10808,7 +10966,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.31, nanoid@npm:^3.3.7, nanoid@npm:^3.3.8": +"nanoid@npm:^3.1.31, nanoid@npm:^3.3.8": version: 3.3.8 resolution: "nanoid@npm:3.3.8" bin: @@ -10825,9 +10983,16 @@ __metadata: linkType: hard "negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 + version: 0.6.4 + resolution: "negotiator@npm:0.6.4" + checksum: 10/d98c04a136583afd055746168f1067d58ce4bfe6e4c73ca1d339567f81ea1f7e665b5bd1e81f4771c67b6c2ea89b21cb2adaea2b16058c7dc31317778f931dab + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 languageName: node linkType: hard @@ -10845,13 +11010,13 @@ __metadata: linkType: hard "nock@npm:^13.3.1": - version: 13.5.5 - resolution: "nock@npm:13.5.5" + version: 13.5.6 + resolution: "nock@npm:13.5.6" dependencies: debug: "npm:^4.1.0" json-stringify-safe: "npm:^5.0.1" propagate: "npm:^2.0.0" - checksum: 10/c19d7bf9654db056357a22b00127bb5606c1bbdff188a5b6c469825e580e31cd0cb0701bce8dd8b4876dbbd36a145fdb681fd69fd59308d6db4923ce8ab2439e + checksum: 10/a57c265b75e5f7767e2f8baf058773cdbf357c31c5fea2761386ec03a008a657f9df921899fe2a9502773b47145b708863b32345aef529b3c45cba4019120f88 languageName: node linkType: hard @@ -10888,19 +11053,19 @@ __metadata: linkType: hard "node-gyp-build@npm:^4.2.0": - version: 4.8.1 - resolution: "node-gyp-build@npm:4.8.1" + version: 4.8.4 + resolution: "node-gyp-build@npm:4.8.4" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: 10/b9297770f96a92e5f2b854f3fd5e4bd418df81d7785a81ab60cec5cf2e5e72dc2c3319808978adc572cfa3885e6b12338cb5f4034bed2cab35f0d76a4b75ccdf + checksum: 10/6a7d62289d1afc419fc8fc9bd00aa4e554369e50ca0acbc215cb91446148b75ff7e2a3b53c2c5b2c09a39d416d69f3d3237937860373104b5fe429bf30ad9ac5 languageName: node linkType: hard -"node-gyp@npm:^10.0.0, node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" +"node-gyp@npm:^10.0.0": + version: 10.3.1 + resolution: "node-gyp@npm:10.3.1" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" @@ -10914,7 +11079,27 @@ __metadata: which: "npm:^4.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe + checksum: 10/d3004f648559e42d7ec8791ea75747fe8a163a6061c202e311e5d7a5f6266baa9a5f5c6fde7be563974c88b030c5d0855fd945364f52fcd230d2a2ceee7be80d + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 11.0.0 + resolution: "node-gyp@npm:11.0.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^14.0.3" + nopt: "npm:^8.0.0" + proc-log: "npm:^5.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.4.3" + which: "npm:^5.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10/5d07430e887a906f85c7c6ed87e8facb7ecd4ce42d948a2438c471df2e24ae6af70f4def114ec1a03127988d164648dda8d75fe666f3c4b431e53856379fdf13 languageName: node linkType: hard @@ -10950,6 +11135,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^8.0.0": + version: 8.0.0 + resolution: "nopt@npm:8.0.0" + dependencies: + abbrev: "npm:^2.0.0" + bin: + nopt: bin/nopt.js + checksum: 10/2d137f64b6f9331ec97047dd1cbbe4dcd9a61ceef4fd0f2252c0bbac1d69ba15671e6fd83a441328824b3ca78afe6ebe1694f12ebcd162b73a221582a06179ff + languageName: node + linkType: hard + "normalize-package-data@npm:^6.0.0": version: 6.0.2 resolution: "normalize-package-data@npm:6.0.2" @@ -11057,10 +11253,10 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.1": - version: 1.13.2 - resolution: "object-inspect@npm:1.13.2" - checksum: 10/7ef65583b6397570a17c56f0c1841e0920e83900f2c94638927abb7b81ac08a19c7aae135bd9dcca96208cac0c7332b4650fb927f027b0cf92d71df2990d0561 +"object-inspect@npm:^1.13.3": + version: 1.13.3 + resolution: "object-inspect@npm:1.13.3" + checksum: 10/14cb973d8381c69e14d7f1c8c75044eb4caf04c6dabcf40ca5c2ce42dc2073ae0bb2a9939eeca142b0c05215afaa1cd5534adb7c8879c32cba2576e045ed8368 languageName: node linkType: hard @@ -11082,14 +11278,16 @@ __metadata: linkType: hard "object.assign@npm:^4.1.4": - version: 4.1.5 - resolution: "object.assign@npm:4.1.5" + version: 4.1.7 + resolution: "object.assign@npm:4.1.7" dependencies: - call-bind: "npm:^1.0.5" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" define-properties: "npm:^1.2.1" - has-symbols: "npm:^1.0.3" + es-object-atoms: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" object-keys: "npm:^1.1.1" - checksum: 10/dbb22da4cda82e1658349ea62b80815f587b47131b3dd7a4ab7f84190ab31d206bbd8fe7e26ae3220c55b65725ac4529825f6142154211220302aa6b1518045d + checksum: 10/3fe28cdd779f2a728a9a66bd688679ba231a2b16646cd1e46b528fe7c947494387dda4bc189eff3417f3717ef4f0a8f2439347cf9a9aa3cef722fbfd9f615587 languageName: node linkType: hard @@ -11186,6 +11384,13 @@ __metadata: languageName: node linkType: hard +"p-map@npm:^7.0.2": + version: 7.0.3 + resolution: "p-map@npm:7.0.3" + checksum: 10/2ef48ccfc6dd387253d71bf502604f7893ed62090b2c9d73387f10006c342606b05233da0e4f29388227b61eb5aeface6197e166520c465c234552eeab2fe633 + languageName: node + linkType: hard + "p-throttle@npm:^4.1.1": version: 4.1.1 resolution: "p-throttle@npm:4.1.1" @@ -11201,9 +11406,9 @@ __metadata: linkType: hard "package-json-from-dist@npm:^1.0.0": - version: 1.0.0 - resolution: "package-json-from-dist@npm:1.0.0" - checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea + version: 1.0.1 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 languageName: node linkType: hard @@ -11330,11 +11535,11 @@ __metadata: linkType: hard "path-to-regexp@npm:^1.7.0": - version: 1.8.0 - resolution: "path-to-regexp@npm:1.8.0" + version: 1.9.0 + resolution: "path-to-regexp@npm:1.9.0" dependencies: isarray: "npm:0.0.1" - checksum: 10/45a01690f72919163cf89714e31a285937b14ad54c53734c826363fcf7beba9d9d0f2de802b4986b1264374562d6a3398a2e5289753a764e3a256494f1e52add + checksum: 10/67f0f4823f7aab356523d93a83f9f8222bdd119fa0b27a8f8b587e8e6c9825294bb4ccd16ae619def111ff3fe5d15ff8f658cdd3b0d58b9c882de6fd15bc1b76 languageName: node linkType: hard @@ -11358,7 +11563,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -11372,6 +11577,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10/ce617b8da36797d09c0baacb96ca8a44460452c89362d7cb8f70ca46b4158ba8bc3606912de7c818eb4a939f7f9015cef3c766ec8a0c6bfc725fdc078e39c717 + languageName: node + linkType: hard + "pify@npm:^5.0.0": version: 5.0.0 resolution: "pify@npm:5.0.0" @@ -11418,14 +11630,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.40": - version: 8.4.41 - resolution: "postcss@npm:8.4.41" +"postcss@npm:^8.4.48": + version: 8.5.1 + resolution: "postcss@npm:8.5.1" dependencies: - nanoid: "npm:^3.3.7" - picocolors: "npm:^1.0.1" - source-map-js: "npm:^1.2.0" - checksum: 10/6e6176c2407eff60493ca60a706c6b7def20a722c3adda94ea1ece38345eb99964191336fd62b62652279cec6938e79e0b1e1d477142c8d3516e7a725a74ee37 + nanoid: "npm:^3.3.8" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10/1fbd28753143f7f03e4604813639918182b15343c7ad0f4e72f3875fc2cc0b8494c887f55dc05008fad5fbf1e1e908ce2edbbce364a91f84dcefb71edf7cd31d languageName: node linkType: hard @@ -11446,17 +11658,17 @@ __metadata: linkType: hard "prettier-plugin-packagejson@npm:^2.4.5": - version: 2.5.2 - resolution: "prettier-plugin-packagejson@npm:2.5.2" + version: 2.5.7 + resolution: "prettier-plugin-packagejson@npm:2.5.7" dependencies: - sort-package-json: "npm:2.10.1" - synckit: "npm:0.9.1" + sort-package-json: "npm:2.13.0" + synckit: "npm:0.9.2" peerDependencies: prettier: ">= 1.16.0" peerDependenciesMeta: prettier: optional: true - checksum: 10/f280d69327a468cd104c72a81134258d3573e56d697a88a5c4498c8d02cecda9a27d9eb3f1d29cc726491782eb3f279c9d41ecf8364a197e20b239c5ccfd0269 + checksum: 10/eca337657660e706134a1509053c39a88249965ff8ec692074c24ad7c2234b878d48c0ccb803e0827a47e676cbeb5ce7845e21f9fbe2c9bdf12e2565b91d0515 languageName: node linkType: hard @@ -11507,6 +11719,13 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^5.0.0": + version: 5.0.0 + resolution: "proc-log@npm:5.0.0" + checksum: 10/35610bdb0177d3ab5d35f8827a429fb1dc2518d9e639f2151ac9007f01a061c30e0c635a970c9b00c39102216160f6ec54b62377c92fac3b7bfc2ad4b98d195c + languageName: node + linkType: hard + "process@npm:^0.11.10": version: 0.11.10 resolution: "process@npm:0.11.10" @@ -11593,9 +11812,11 @@ __metadata: linkType: hard "psl@npm:^1.1.33": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 10/d07879d4bfd0ac74796306a8e5a36a93cfb9c4f4e8ee8e63fbb909066c192fe1008cd8f12abd8ba2f62ca28247949a20c8fb32e1d18831d9e71285a1569720f9 + version: 1.15.0 + resolution: "psl@npm:1.15.0" + dependencies: + punycode: "npm:^2.3.1" + checksum: 10/5e7467eb5196eb7900d156783d12907d445c0122f76c73203ce96b148a6ccf8c5450cc805887ffada38ff92d634afcf33720c24053cb01d5b6598d1c913c5caf languageName: node linkType: hard @@ -11616,7 +11837,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 @@ -11624,11 +11845,11 @@ __metadata: linkType: hard "qs@npm:^6.11.2": - version: 6.13.0 - resolution: "qs@npm:6.13.0" + version: 6.14.0 + resolution: "qs@npm:6.14.0" dependencies: - side-channel: "npm:^1.0.6" - checksum: 10/f548b376e685553d12e461409f0d6e5c59ec7c7d76f308e2a888fd9db3e0c5e89902bedd0754db3a9038eda5f27da2331a6f019c8517dc5e0a16b3c9a6e9cef8 + side-channel: "npm:^1.1.0" + checksum: 10/a60e49bbd51c935a8a4759e7505677b122e23bf392d6535b8fc31c1e447acba2c901235ecb192764013cd2781723dc1f61978b5fdd93cc31d7043d31cdc01974 languageName: node linkType: hard @@ -11748,15 +11969,15 @@ __metadata: linkType: hard "readable-stream@npm:^3.6.2 || ^4.4.2": - version: 4.5.2 - resolution: "readable-stream@npm:4.5.2" + version: 4.7.0 + resolution: "readable-stream@npm:4.7.0" dependencies: abort-controller: "npm:^3.0.0" buffer: "npm:^6.0.3" events: "npm:^3.3.0" process: "npm:^0.11.10" string_decoder: "npm:^1.3.0" - checksum: 10/01b128a559c5fd76a898495f858cf0a8839f135e6a69e3409f986e88460134791657eb46a2ff16826f331682a3c4d0c5a75cef5e52ef259711021ba52b1c2e82 + checksum: 10/bdf096c8ff59452ce5d08f13da9597f9fcfe400b4facfaa88e74ec057e5ad1fdfa140ffe28e5ed806cf4d2055f0b812806e962bca91dce31bc4cef08e53be3a4 languageName: node linkType: hard @@ -11881,7 +12102,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.22.8, resolve@npm:^1.20.0, resolve@npm:^1.22.3, resolve@npm:^1.22.4": +"resolve@npm:1.22.8": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -11894,7 +12115,20 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.3#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@npm:^1.20.0, resolve@npm:^1.22.3, resolve@npm:^1.22.4": + version: 1.22.10 + resolution: "resolve@npm:1.22.10" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A1.22.8#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -11907,6 +12141,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.3#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": + version: 1.22.10 + resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a + languageName: node + linkType: hard + "responselike@npm:^2.0.0": version: 2.0.1 resolution: "responselike@npm:2.0.1" @@ -12015,7 +12262,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -12029,6 +12276,17 @@ __metadata: languageName: node linkType: hard +"safe-regex-test@npm:^1.1.0": + version: 1.1.0 + resolution: "safe-regex-test@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + is-regex: "npm:^1.2.1" + checksum: 10/ebdb61f305bf4756a5b023ad86067df5a11b26898573afe9e52a548a63c3bd594825d9b0e2dde2eb3c94e57e0e04ac9929d4107c394f7b8e56a4613bed46c69a + languageName: node + linkType: hard + "safe-stable-stringify@npm:^2.4.3": version: 2.5.0 resolution: "safe-stable-stringify@npm:2.5.0" @@ -12107,15 +12365,15 @@ __metadata: linkType: hard "ses@npm:^1.1.0": - version: 1.7.0 - resolution: "ses@npm:1.7.0" + version: 1.10.0 + resolution: "ses@npm:1.10.0" dependencies: - "@endo/env-options": "npm:^1.1.5" - checksum: 10/8d1227fadcd06653d1b49083c067ae07e55164af984c9e8b393238fbbd315f47216472e3ac65a78638955f3f1a2537e9c9865f0ab142639a6862b902cb1cf6f2 + "@endo/env-options": "npm:^1.1.8" + checksum: 10/57073350cab333e3c4516e8ea09e1ddd2f81fdd954dc48798548d098550d1da8bb3266def0461a34a4e11c0a1027bde03e05f2ac5feb512ff3fc33dd327a9bb2 languageName: node linkType: hard -"set-function-length@npm:^1.2.1": +"set-function-length@npm:^1.2.2": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" dependencies: @@ -12197,15 +12455,51 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.6": - version: 1.0.6 - resolution: "side-channel@npm:1.0.6" +"side-channel-list@npm:^1.0.0": + version: 1.0.0 + resolution: "side-channel-list@npm:1.0.0" dependencies: - call-bind: "npm:^1.0.7" es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.4" - object-inspect: "npm:^1.13.1" - checksum: 10/eb10944f38cebad8ad643dd02657592fa41273ce15b8bfa928d3291aff2d30c20ff777cfe908f76ccc4551ace2d1245822fdc576657cce40e9066c638ca8fa4d + object-inspect: "npm:^1.13.3" + checksum: 10/603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + side-channel-list: "npm:^1.0.0" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba languageName: node linkType: hard @@ -12281,13 +12575,6 @@ __metadata: languageName: node linkType: hard -"slash@npm:^4.0.0": - version: 4.0.0 - resolution: "slash@npm:4.0.0" - checksum: 10/da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d - languageName: node - linkType: hard - "slashes@npm:^3.0.12": version: 3.0.12 resolution: "slashes@npm:3.0.12" @@ -12314,13 +12601,13 @@ __metadata: linkType: hard "socks-proxy-agent@npm:^8.0.3": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" dependencies: - agent-base: "npm:^7.1.1" + agent-base: "npm:^7.1.2" debug: "npm:^4.3.4" socks: "npm:^2.8.3" - checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7 + checksum: 10/ee99e1dacab0985b52cbe5a75640be6e604135e9489ebdc3048635d186012fbaecc20fbbe04b177dee434c319ba20f09b3e7dfefb7d932466c0d707744eac05c languageName: node linkType: hard @@ -12341,28 +12628,28 @@ __metadata: languageName: node linkType: hard -"sort-package-json@npm:2.10.1": - version: 2.10.1 - resolution: "sort-package-json@npm:2.10.1" +"sort-package-json@npm:2.13.0": + version: 2.13.0 + resolution: "sort-package-json@npm:2.13.0" dependencies: detect-indent: "npm:^7.0.1" detect-newline: "npm:^4.0.0" get-stdin: "npm:^9.0.0" git-hooks-list: "npm:^3.0.0" - globby: "npm:^13.1.2" is-plain-obj: "npm:^4.1.0" semver: "npm:^7.6.0" sort-object-keys: "npm:^1.1.3" + tinyglobby: "npm:^0.2.9" bin: sort-package-json: cli.js - checksum: 10/3a08cb9227c244d51bfb0eaaa5a9ea82fd3c96ea299c040365700b3f445d46a98411df4237f4e3c96ba67be4dcd53931747eab3b799f0335d278b36d64f1061d + checksum: 10/06081222ca6a0affddb613d6ee703012aba460b3b41930a229b1ba222f5829fc5dba996b69e229c198164112600455dc3178bbd7819f80c33503dbea61f67fac languageName: node linkType: hard -"source-map-js@npm:^1.2.0": - version: 1.2.0 - resolution: "source-map-js@npm:1.2.0" - checksum: 10/74f331cfd2d121c50790c8dd6d3c9de6be21926de80583b23b37029b0f37aefc3e019fa91f9a10a5e120c08135297e1ecf312d561459c45908cb1e0e365f49e5 +"source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3 languageName: node linkType: hard @@ -12428,9 +12715,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.20 - resolution: "spdx-license-ids@npm:3.0.20" - checksum: 10/30e566ea74b04232c64819d1f5313c00d92e9c73d054541650331fc794499b3bcc4991bcd90fa3c2fc4d040006f58f63104706255266e87a9d452e6574afc60c + version: 3.0.21 + resolution: "spdx-license-ids@npm:3.0.21" + checksum: 10/17a033b4c3485f081fc9faa1729dde8782a85d9131b156f2397c71256c2e1663132857d3cba1457c4965f179a4dcf1b69458a31e9d3d0c766d057ef0e3a0b4f2 languageName: node linkType: hard @@ -12457,6 +12744,15 @@ __metadata: languageName: node linkType: hard +"ssri@npm:^12.0.0": + version: 12.0.0 + resolution: "ssri@npm:12.0.0" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10/7024c1a6e39b3f18aa8f1c8290e884fe91b0f9ca5a6c6d410544daad54de0ba664db879afe16412e187c6c292fd60b937f047ee44292e5c2af2dcc6d8e1a9b48 + languageName: node + linkType: hard + "ssri@npm:^6.0.1": version: 6.0.2 resolution: "ssri@npm:6.0.2" @@ -12483,8 +12779,8 @@ __metadata: linkType: hard "streamx@npm:^2.15.0": - version: 2.19.0 - resolution: "streamx@npm:2.19.0" + version: 2.21.1 + resolution: "streamx@npm:2.21.1" dependencies: bare-events: "npm:^2.2.0" fast-fifo: "npm:^1.3.2" @@ -12493,7 +12789,7 @@ __metadata: dependenciesMeta: bare-events: optional: true - checksum: 10/3e57a12402200cce347bd0658b5e7ef14a41636341256d2a9f43100e5c4f5d82166a4df77aef92082686150805a1b14f74370f3c96b4ed3d6d9889da1e3b3c21 + checksum: 10/d61ee82033f8b900226e2405aeb683de5f51a68ded1d40198d548cd9a7b2e47b7706442c9142bbc7fc59874f03063ee41ddf9e8667e63186b507b2e6b394ac28 languageName: node linkType: hard @@ -12642,17 +12938,7 @@ __metadata: languageName: node linkType: hard -"synckit@npm:0.9.1": - version: 0.9.1 - resolution: "synckit@npm:0.9.1" - dependencies: - "@pkgr/core": "npm:^0.1.0" - tslib: "npm:^2.6.2" - checksum: 10/bff3903976baf8b699b5483228116d70223781a93b17c70e685c277ee960cdfd1a09cb5a741e6a9ec35e2428f14f4664baec41ccc99a598f267608b2a54f529b - languageName: node - linkType: hard - -"synckit@npm:^0.9.1": +"synckit@npm:0.9.2, synckit@npm:^0.9.1": version: 0.9.2 resolution: "synckit@npm:0.9.2" dependencies: @@ -12707,6 +12993,20 @@ __metadata: languageName: node linkType: hard +"tar@npm:^7.4.3": + version: 7.4.3 + resolution: "tar@npm:7.4.3" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.0.1" + mkdirp: "npm:^3.0.1" + yallist: "npm:^5.0.0" + checksum: 10/12a2a4fc6dee23e07cc47f1aeb3a14a1afd3f16397e1350036a8f4cdfee8dcac7ef5978337a4e7b2ac2c27a9a6d46388fc2088ea7c80cb6878c814b1425f8ecf + languageName: node + linkType: hard + "tau-prolog@npm:^0.2.66": version: 0.2.81 resolution: "tau-prolog@npm:0.2.81" @@ -12739,11 +13039,11 @@ __metadata: linkType: hard "text-decoder@npm:^1.1.0": - version: 1.1.1 - resolution: "text-decoder@npm:1.1.1" + version: 1.2.3 + resolution: "text-decoder@npm:1.2.3" dependencies: b4a: "npm:^1.6.4" - checksum: 10/c6981b93850daeafc8bd1dbd8f984d4fb2d14632f450de0892692b5bbee2d2f4cbef8a807142527370649fd357f58491ede4915d43669eca624cb52b8dd247b6 + checksum: 10/bcdec33c0f070aeac38e46e4cafdcd567a58473ed308bdf75260bfbd8f7dc76acbc0b13226afaec4a169d0cb44cec2ab89c57b6395ccf02e941eaebbe19e124a languageName: node linkType: hard @@ -12764,6 +13064,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.9": + version: 0.2.10 + resolution: "tinyglobby@npm:0.2.10" + dependencies: + fdir: "npm:^6.4.2" + picomatch: "npm:^4.0.2" + checksum: 10/10c976866d849702edc47fc3fef27d63f074c40f75ef17171ecc1452967900699fa1e62373681dd58e673ddff2e3f6094bcd0a2101e3e4b30f4c2b9da41397f2 + languageName: node + linkType: hard + "tinylogic@npm:^2.0.0": version: 2.0.0 resolution: "tinylogic@npm:2.0.0" @@ -12902,14 +13212,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.4.0": - version: 2.4.0 - resolution: "tslib@npm:2.4.0" - checksum: 10/d8379e68b36caf082c1905ec25d17df8261e1d68ddc1abfd6c91158a064f6e4402039ae7c02cf4c81d12e3a2a2c7cd8ea2f57b233eb80136a2e3e7279daf2911 +"tslib@npm:2.7.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10/9a5b47ddac65874fa011c20ff76db69f97cf90c78cff5934799ab8894a5342db2d17b4e7613a087046bc1d133d21547ddff87ac558abeec31ffa929c88b7fce6 languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3": +"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 @@ -12960,6 +13270,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:4.30.0": + version: 4.30.0 + resolution: "type-fest@npm:4.30.0" + checksum: 10/46c733df4feb87dfd281fba4fa3913dc38b45136be35adffbcef95e13414105a4669476c1f8686680b9c98e59ed5dc85efe42caf67adbaa04f48dfc41f8330fa + languageName: node + linkType: hard + "type-fest@npm:^0.12.0": version: 0.12.0 resolution: "type-fest@npm:0.12.0" @@ -12982,9 +13299,9 @@ __metadata: linkType: hard "type-fest@npm:^4.0.0": - version: 4.25.0 - resolution: "type-fest@npm:4.25.0" - checksum: 10/16ddf51dbfeef45e6f0a139c16f06d6cd05b61be76b048c41e79997f150a66422219d7ec10a2717ab926505402d59b1ddc8560f5f6c245e1b8a35971c2f1b754 + version: 4.32.0 + resolution: "type-fest@npm:4.32.0" + checksum: 10/7cee33a2d82c992e97e85eca4016a7dd62239fc6f95a7f86d46671900cad594eda832d97a1d4231d3bb2ed7ff5144c5f3cf4644e1f722faa4e6decef0c5276ca languageName: node linkType: hard @@ -13030,16 +13347,16 @@ __metadata: linkType: hard "typescript-eslint@npm:^8.7.0": - version: 8.19.1 - resolution: "typescript-eslint@npm:8.19.1" + version: 8.20.0 + resolution: "typescript-eslint@npm:8.20.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.19.1" - "@typescript-eslint/parser": "npm:8.19.1" - "@typescript-eslint/utils": "npm:8.19.1" + "@typescript-eslint/eslint-plugin": "npm:8.20.0" + "@typescript-eslint/parser": "npm:8.20.0" + "@typescript-eslint/utils": "npm:8.20.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/3e7861bcd47c0bea962662d5f18a9f9214270057c082f2e3839ee2f681a42018395755216005d2408447de5b96892b6a18cc794daf8663bba1753def48e6756c + checksum: 10/5d72ec36d9a6a519cedb003af28bdad37560999a6f8a126193098ff403d6cc6947f3f27d09171d446bc62e43a1aeb00563ce1adfc85014a011993bfa2c95a20f languageName: node linkType: hard @@ -13077,12 +13394,17 @@ __metadata: languageName: node linkType: hard -"undici@npm:5.28.4": - version: 5.28.4 - resolution: "undici@npm:5.28.4" - dependencies: - "@fastify/busboy": "npm:^2.0.0" - checksum: 10/a666a9f5ac4270c659fafc33d78b6b5039a0adbae3e28f934774c85dcc66ea91da907896f12b414bd6f578508b44d5dc206fa636afa0e49a4e1c9e99831ff065 +"undici-types@npm:~6.20.0": + version: 6.20.0 + resolution: "undici-types@npm:6.20.0" + checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe + languageName: node + linkType: hard + +"undici@npm:6.19.7": + version: 6.19.7 + resolution: "undici@npm:6.19.7" + checksum: 10/77fb8b0377388f6dba8244b015841318d621031211b4f3c2273d809304b77ec44adeba4b89dfd6708bdc044190e18f068e5b231882ef15d057d4624e46f544e3 languageName: node linkType: hard @@ -13095,6 +13417,15 @@ __metadata: languageName: node linkType: hard +"unique-filename@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-filename@npm:4.0.0" + dependencies: + unique-slug: "npm:^5.0.0" + checksum: 10/6a62094fcac286b9ec39edbd1f8f64ff92383baa430af303dfed1ffda5e47a08a6b316408554abfddd9730c78b6106bef4ca4d02c1231a735ddd56ced77573df + languageName: node + linkType: hard + "unique-slug@npm:^4.0.0": version: 4.0.0 resolution: "unique-slug@npm:4.0.0" @@ -13104,6 +13435,15 @@ __metadata: languageName: node linkType: hard +"unique-slug@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-slug@npm:5.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10/beafdf3d6f44990e0a5ce560f8f881b4ee811be70b6ba0db25298c31c8cf525ed963572b48cd03be1c1349084f9e339be4241666d7cf1ebdad20598d3c652b27 + languageName: node + linkType: hard + "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" @@ -13385,16 +13725,17 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.2": - version: 1.1.15 - resolution: "which-typed-array@npm:1.1.15" +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.2": + version: 1.1.18 + resolution: "which-typed-array@npm:1.1.18" dependencies: available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" + gopd: "npm:^1.2.0" has-tostringtag: "npm:^1.0.2" - checksum: 10/c3b6a99beadc971baa53c3ee5b749f2b9bdfa3b3b9a70650dd8511a48b61d877288b498d424712e9991d16019633086bd8b5923369460d93463c5825fa36c448 + checksum: 10/11eed801b2bd08cdbaecb17aff381e0fb03526532f61acc06e6c7b9370e08062c33763a51f27825f13fdf34aabd0df6104007f4e8f96e6eaef7db0ce17a26d6e languageName: node linkType: hard @@ -13442,6 +13783,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^5.0.0": + version: 5.0.0 + resolution: "which@npm:5.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10/6ec99e89ba32c7e748b8a3144e64bfc74aa63e2b2eacbb61a0060ad0b961eb1a632b08fb1de067ed59b002cec3e21de18299216ebf2325ef0f78e0f121e14e90 + languageName: node + linkType: hard + "widest-line@npm:^3.1.0": version: 3.1.0 resolution: "widest-line@npm:3.1.0" @@ -13609,6 +13961,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10/1884d272d485845ad04759a255c71775db0fac56308764b4c77ea56a20d56679fad340213054c8c9c9c26fcfd4c4b2a90df993b7e0aaf3cdb73c618d1d1a802a + languageName: node + linkType: hard + "yaml@npm:^1.10.0": version: 1.10.2 resolution: "yaml@npm:1.10.2" @@ -13617,11 +13976,11 @@ __metadata: linkType: hard "yaml@npm:^2.2.2": - version: 2.5.0 - resolution: "yaml@npm:2.5.0" + version: 2.7.0 + resolution: "yaml@npm:2.7.0" bin: yaml: bin.mjs - checksum: 10/72e903fdbe3742058885205db4a6c9ff38e5f497f4e05e631264f7756083c05e7d10dfb5e4ce9d7a95de95338f9b20d19dd0b91c60c65f7d7608b6b3929820ad + checksum: 10/c8c314c62fbd49244a6a51b06482f6d495b37ab10fa685fcafa1bbaae7841b7233ee7d12cab087bcca5a0b28adc92868b6e437322276430c28d00f1c1732eeec languageName: node linkType: hard From a32a95b3403fe3bda4080d568d4a726b3981f13b Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 15 Jan 2025 14:18:09 -0800 Subject: [PATCH 135/146] eslint thresholds --- eslint-warning-thresholds.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/eslint-warning-thresholds.json b/eslint-warning-thresholds.json index 5de1f036ef7..58fa581cf06 100644 --- a/eslint-warning-thresholds.json +++ b/eslint-warning-thresholds.json @@ -3,24 +3,24 @@ "@typescript-eslint/no-base-to-string": 3, "@typescript-eslint/no-duplicate-enum-values": 2, "@typescript-eslint/no-unsafe-enum-comparison": 34, - "@typescript-eslint/no-unused-vars": 36, - "@typescript-eslint/prefer-promise-reject-errors": 13, - "@typescript-eslint/prefer-readonly": 145, - "@typescript-eslint/switch-exhaustiveness-check": 9, + "@typescript-eslint/no-unused-vars": 41, + "@typescript-eslint/prefer-promise-reject-errors": 33, + "@typescript-eslint/prefer-readonly": 147, + "@typescript-eslint/switch-exhaustiveness-check": 0, "import-x/namespace": 189, "import-x/no-named-as-default": 1, "import-x/no-named-as-default-member": 8, - "import-x/order": 205, - "jest/no-conditional-in-test": 129, + "import-x/order": 211, + "jest/no-conditional-in-test": 138, "jest/prefer-lowercase-title": 2, "jest/prefer-strict-equal": 2, "jsdoc/check-tag-names": 375, - "jsdoc/require-returns": 22, - "jsdoc/tag-lines": 328, + "jsdoc/require-returns": 25, + "jsdoc/tag-lines": 335, "n/no-unsupported-features/node-builtins": 18, "n/prefer-global/text-encoder": 4, "n/prefer-global/text-decoder": 4, - "prettier/prettier": 115, + "prettier/prettier": 118, "promise/always-return": 3, "promise/catch-or-return": 2, "promise/param-names": 8, From 36449e9892c883f687154ac0bb54043b161e8d7c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 15 Jan 2025 14:25:26 -0800 Subject: [PATCH 136/146] fix coverage --- ...-permission-adapter-session-scopes.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts index 8dd377f0eda..62b183f5185 100644 --- a/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts +++ b/packages/multichain/src/adapters/caip-permission-adapter-session-scopes.test.ts @@ -94,6 +94,25 @@ describe('CAIP-25 session scopes adapters', () => { }); }); + it('returns a NormalizedScopesObject with empty methods and notifications for scope not wallet namespace and unknown reference', () => { + const result = getSessionScopes({ + requiredScopes: {}, + optionalScopes: { + 'foo:1': { + accounts: ['foo:1:0xdeadbeef'], + }, + }, + }); + + expect(result).toStrictEqual({ + 'foo:1': { + methods: [], + notifications: [], + accounts: ['foo:1:0xdeadbeef'], + }, + }); + }); + it('returns a NormalizedScopesObject for a eip155 namespaced scope', () => { const result = getSessionScopes({ requiredScopes: {}, From 8fff3517262e111dc2702e0b5f5acfa42b153cde Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 16 Jan 2025 09:21:41 -0600 Subject: [PATCH 137/146] update lock file --- yarn.lock | 2373 +++++++++++++++++++++++------------------------------ 1 file changed, 1007 insertions(+), 1366 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6a417de7c06..c386c0a1343 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,10 +193,10 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.26.5": - version: 7.26.5 - resolution: "@babel/compat-data@npm:7.26.5" - checksum: 10/afe35751f27bda80390fa221d5e37be55b7fc42cec80de9896086e20394f2306936c4296fcb4d62b683e3b49ba2934661ea7e06196ca2dacdc2e779fbea4a1a9 +"@babel/compat-data@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/compat-data@npm:7.26.3" + checksum: 10/0bf4e491680722aa0eac26f770f2fae059f92e2ac083900b241c90a2c10f0fc80e448b1feccc2b332687fab4c3e33e9f83dee9ef56badca1fb9f3f71266d9ebf languageName: node linkType: hard @@ -223,65 +223,65 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.5, @babel/generator@npm:^7.7.2": - version: 7.26.5 - resolution: "@babel/generator@npm:7.26.5" +"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.3, @babel/generator@npm:^7.7.2": + version: 7.26.3 + resolution: "@babel/generator@npm:7.26.3" dependencies: - "@babel/parser": "npm:^7.26.5" - "@babel/types": "npm:^7.26.5" + "@babel/parser": "npm:^7.26.3" + "@babel/types": "npm:^7.26.3" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10/aa5f176155431d1fb541ca11a7deddec0fc021f20992ced17dc2f688a0a9584e4ff4280f92e8a39302627345cd325762f70f032764806c579c6fd69432542bcb + checksum: 10/c1d8710cc1c52af9d8d67f7d8ea775578aa500887b327d2a81e27494764a6ef99e438dd7e14cf7cd3153656492ee27a8362980dc438087c0ca39d4e75532c638 languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" +"@babel/helper-annotate-as-pure@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.25.9" - checksum: 10/41edda10df1ae106a9b4fe617bf7c6df77db992992afd46192534f5cff29f9e49a303231733782dd65c5f9409714a529f215325569f14282046e9d3b7a1ffb6c + "@babel/types": "npm:^7.24.7" + checksum: 10/a9017bfc1c4e9f2225b967fbf818004703de7cf29686468b54002ffe8d6b56e0808afa20d636819fcf3a34b89ba72f52c11bdf1d69f303928ee10d92752cad95 languageName: node linkType: hard "@babel/helper-compilation-targets@npm:^7.25.9": - version: 7.26.5 - resolution: "@babel/helper-compilation-targets@npm:7.26.5" + version: 7.25.9 + resolution: "@babel/helper-compilation-targets@npm:7.25.9" dependencies: - "@babel/compat-data": "npm:^7.26.5" + "@babel/compat-data": "npm:^7.25.9" "@babel/helper-validator-option": "npm:^7.25.9" browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10/f3b5f0bfcd7b6adf03be1a494b269782531c6e415afab2b958c077d570371cf1bfe001c442508092c50ed3711475f244c05b8f04457d8dea9c34df2b741522bf + checksum: 10/8053fbfc21e8297ab55c8e7f9f119e4809fa7e505268691e1bedc2cf5e7a5a7de8c60ad13da2515378621b7601c42e101d2d679904da395fa3806a1edef6b92e languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" +"@babel/helper-create-class-features-plugin@npm:^7.25.0": + version: 7.25.4 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.25.9" - "@babel/helper-member-expression-to-functions": "npm:^7.25.9" - "@babel/helper-optimise-call-expression": "npm:^7.25.9" - "@babel/helper-replace-supers": "npm:^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.4" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10/d1d47a7b5fd317c6cb1446b0e4f4892c19ddaa69ea0229f04ba8bea5f273fc8168441e7114ad36ff919f2d310f97310cec51adc79002e22039a7e1640ccaf248 + checksum: 10/47218da9fd964af30d41f0635d9e33eed7518e03aa8f10c3eb8a563bb2c14f52be3e3199db5912ae0e26058c23bb511c811e565c55ecec09427b04b867ed13c2 languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" +"@babel/helper-member-expression-to-functions@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10/ef8cc1c1e600b012b312315f843226545a1a89f25d2f474ce2503fd939ca3f8585180f291a3a13efc56cf13eddc1d41a3a040eae9a521838fd59a6d04cc82490 + "@babel/traverse": "npm:^7.24.8" + "@babel/types": "npm:^7.24.8" + checksum: 10/ac878761cfd0a46c081cda0da75cc186f922cf16e8ecdd0c4fb6dca4330d9fe4871b41a9976224cf9669c9e7fe0421b5c27349f2e99c125fa0be871b327fa770 languageName: node linkType: hard @@ -295,7 +295,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.26.0": +"@babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.26.0": version: 7.26.0 resolution: "@babel/helper-module-transforms@npm:7.26.0" dependencies: @@ -308,42 +308,52 @@ __metadata: languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" +"@babel/helper-optimise-call-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.25.9" - checksum: 10/f09d0ad60c0715b9a60c31841b3246b47d67650c512ce85bbe24a3124f1a4d66377df793af393273bc6e1015b0a9c799626c48e53747581c1582b99167cc65dc + "@babel/types": "npm:^7.24.7" + checksum: 10/da7a7f2d1bb1be4cffd5fa820bd605bc075c7dd014e0458f608bb6f34f450fe9412c8cea93e788227ab396e0e02c162d7b1db3fbcb755a6360e354c485d61df0 languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.26.5, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.26.5 - resolution: "@babel/helper-plugin-utils@npm:7.26.5" - checksum: 10/1cc0fd8514da3bb249bed6c27227696ab5e84289749d7258098701cffc0c599b7f61ec40dd332f8613030564b79899d9826813c96f966330bcfc7145a8377857 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.24.8 + resolution: "@babel/helper-plugin-utils@npm:7.24.8" + checksum: 10/adbc9fc1142800a35a5eb0793296924ee8057fe35c61657774208670468a9fbfbb216f2d0bc46c680c5fefa785e5ff917cc1674b10bd75cdf9a6aa3444780630 languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.25.9": - version: 7.26.5 - resolution: "@babel/helper-replace-supers@npm:7.26.5" +"@babel/helper-replace-supers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-replace-supers@npm:7.25.0" dependencies: - "@babel/helper-member-expression-to-functions": "npm:^7.25.9" - "@babel/helper-optimise-call-expression": "npm:^7.25.9" - "@babel/traverse": "npm:^7.26.5" + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10/cfb911d001a8c3d2675077dbb74ee8d7d5533b22d74f8d775cefabf19c604f6cbc22cfeb94544fe8efa626710d920f04acb22923017e68f46f5fdb1cb08b32ad + checksum: 10/97c6c17780cb9692132f7243f5a21fb6420104cb8ff8752dc03cfc9a1912a243994c0290c77ff096637ab6f2a7363b63811cfc68c2bad44e6b39460ac2f6a63f languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" +"@babel/helper-simple-access@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-simple-access@npm:7.24.7" dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10/fdbb5248932198bc26daa6abf0d2ac42cab9c2dbb75b7e9f40d425c8f28f09620b886d40e7f9e4e08ffc7aaa2cefe6fc2c44be7c20e81f7526634702fb615bdc + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10/5083e190186028e48fc358a192e4b93ab320bd016103caffcfda81302a13300ccce46c9cd255ae520c25d2a6a9b47671f93e5fe5678954a2329dc0a685465c49 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10/784a6fdd251a9a7e42ccd04aca087ecdab83eddc60fda76a2950e00eb239cc937d3c914266f0cc476298b52ac3f44ffd04c358e808bd17552a7e008d75494a77 languageName: node linkType: hard @@ -361,7 +371,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.25.9": +"@babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-option@npm:7.25.9" checksum: 10/9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d @@ -378,14 +388,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.5": - version: 7.26.5 - resolution: "@babel/parser@npm:7.26.5" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/parser@npm:7.26.3" dependencies: - "@babel/types": "npm:^7.26.5" + "@babel/types": "npm:^7.26.3" bin: parser: ./bin/babel-parser.js - checksum: 10/d92097066e3e26625a485149f54c27899e4d94d7ef2f76d8fc9de2019212e7951940a31c0003f26ccad22e664f89ff51e5d5fe80a11eafaaec2420655010533c + checksum: 10/e7e3814b2dc9ee3ed605d38223471fa7d3a84cbe9474d2b5fa7ac57dc1ddf75577b1fd3a93bf7db8f41f28869bda795cddd80223f980be23623b6434bf4c88a8 languageName: node linkType: hard @@ -434,13 +444,13 @@ __metadata: linkType: hard "@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.26.0 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" + version: 7.24.7 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/c122aa577166c80ee67f75aebebeef4150a132c4d3109d25d7fc058bf802946f883e330f20b78c1d3e3a5ada631c8780c263d2d01b5dbaecc69efefeedd42916 + checksum: 10/22fc50bd85a491bb8d22065f330a41f60d66f2f2d7a1deb73e80c8a4b5d7a42a092a03f8da18800650eca0fc14585167cc4e5c9fab351f0d390d1592347162ae languageName: node linkType: hard @@ -466,14 +476,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-syntax-jsx@npm:7.25.9" +"@babel/plugin-syntax-jsx@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/bb609d1ffb50b58f0c1bac8810d0e46a4f6c922aa171c458f3a19d66ee545d36e782d3bffbbc1fed0dc65a558bdce1caf5279316583c0fff5a2c1658982a8563 + checksum: 10/a93516ae5b34868ab892a95315027d4e5e38e8bd1cfca6158f2974b0901cbb32bbe64ea10ad5b25f919ddc40c6d8113c4823372909c9c9922170c12b0b1acecb languageName: node linkType: hard @@ -565,65 +575,66 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.25.9, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.25.9 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" +"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.25.4 + resolution: "@babel/plugin-syntax-typescript@npm:7.25.4" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 + checksum: 10/0771b45a35fd536cd3b3a48e5eda0f53e2d4f4a0ca07377cc247efa39eaf6002ed1c478106aad2650e54aefaebcb4f34f3284c4ae9252695dbd944bf66addfb0 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.23.3, @babel/plugin-transform-modules-commonjs@npm:^7.25.9": - version: 7.26.3 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.26.3" +"@babel/plugin-transform-modules-commonjs@npm:^7.23.3, @babel/plugin-transform-modules-commonjs@npm:^7.24.7": + version: 7.24.8 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" dependencies: - "@babel/helper-module-transforms": "npm:^7.26.0" - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-module-transforms": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-simple-access": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/f817f02fa04d13f1578f3026239b57f1003bebcf9f9b8d854714bed76a0e4986c79bd6d2e0ac14282c5d309454a8dab683c179709ca753b0152a69c69f3a78e3 + checksum: 10/18e5d229767c7b5b6ff0cbf1a8d2d555965b90201839d0ac2dc043b56857624ea344e59f733f028142a8c1d54923b82e2a0185694ef36f988d797bfbaf59819c languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.25.9": - version: 7.26.5 - resolution: "@babel/plugin-transform-typescript@npm:7.26.5" +"@babel/plugin-transform-typescript@npm:^7.24.7": + version: 7.25.2 + resolution: "@babel/plugin-transform-typescript@npm:7.25.2" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.25.9" - "@babel/helper-create-class-features-plugin": "npm:^7.25.9" - "@babel/helper-plugin-utils": "npm:^7.26.5" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" - "@babel/plugin-syntax-typescript": "npm:^7.25.9" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-create-class-features-plugin": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/plugin-syntax-typescript": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/28c315ed51cf6a23e14181ee8b265e6ae5bc474cd604e6dac5a4fa5aed114447972690a7d327d8f8e679b7fa18e52218fced0e2a039e4eb854c6016f00dff956 + checksum: 10/50e017ffd131c08661daa22b6c759999bb7a6cdfbf683291ee4bcbea4ae839440b553d2f8896bcf049aca1d267b39f3b09e8336059e919e83149b5ad859671f6 languageName: node linkType: hard "@babel/preset-typescript@npm:^7.23.3": - version: 7.26.0 - resolution: "@babel/preset-typescript@npm:7.26.0" + version: 7.24.7 + resolution: "@babel/preset-typescript@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - "@babel/helper-validator-option": "npm:^7.25.9" - "@babel/plugin-syntax-jsx": "npm:^7.25.9" - "@babel/plugin-transform-modules-commonjs": "npm:^7.25.9" - "@babel/plugin-transform-typescript": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" + "@babel/plugin-syntax-jsx": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7" + "@babel/plugin-transform-typescript": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/81a60826160163a3daae017709f42147744757b725b50c9024ef3ee5a402ee45fd2e93eaecdaaa22c81be91f7940916249cfb7711366431cfcacc69c95878c03 + checksum: 10/995e9783f8e474581e7533d6b10ec1fbea69528cc939ad8582b5937e13548e5215d25a8e2c845e7b351fdaa13139896b5e42ab3bde83918ea4e41773f10861ac languageName: node linkType: hard "@babel/runtime@npm:^7.23.9": - version: 7.26.0 - resolution: "@babel/runtime@npm:7.26.0" + version: 7.25.4 + resolution: "@babel/runtime@npm:7.25.4" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10/9f4ea1c1d566c497c052d505587554e782e021e6ccd302c2ad7ae8291c8e16e3f19d4a7726fb64469e057779ea2081c28b7dbefec6d813a22f08a35712c0f699 + checksum: 10/70d2a420c24a3289ea6c4addaf3a1c4186bc3d001c92445faa3cd7601d7d2fbdb32c63b3a26b9771e20ff2f511fa76b726bf256f823cdb95bc37b8eadbd02f70 languageName: node linkType: hard @@ -638,28 +649,28 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.5, @babel/traverse@npm:^7.7.2": - version: 7.26.5 - resolution: "@babel/traverse@npm:7.26.5" +"@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.7.2": + version: 7.26.4 + resolution: "@babel/traverse@npm:7.26.4" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.5" - "@babel/parser": "npm:^7.26.5" + "@babel/generator": "npm:^7.26.3" + "@babel/parser": "npm:^7.26.3" "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.5" + "@babel/types": "npm:^7.26.3" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10/b0131159450e3cd4208354cdea57e832e1a344fcc284b6ac84d1e13567a10501c4747bfd0ce637d2bd02277526b49372cfca71edd5c825cea74dcc9f52bb9225 + checksum: 10/30c81a80d66fc39842814bc2e847f4705d30f3859156f130d90a0334fe1d53aa81eed877320141a528ecbc36448acc0f14f544a7d410fa319d1c3ab63b50b58f languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.5, @babel/types@npm:^7.3.3": - version: 7.26.5 - resolution: "@babel/types@npm:7.26.5" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.3, @babel/types@npm:^7.3.3": + version: 7.26.3 + resolution: "@babel/types@npm:7.26.3" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/148f6bead7bc39371176ba681873c930087503a8bfd2b0dab5090de32752241806c95f4e87cee8b2976bb0277c6cbc150f16c333fc90269634b711d3711c0f18 + checksum: 10/c31d0549630a89abfa11410bf82a318b0c87aa846fbf5f9905e47ba5e2aa44f41cc746442f105d622c519e4dc532d35a8d8080460ff4692f9fc7485fbf3a00eb languageName: node linkType: hard @@ -671,29 +682,29 @@ __metadata: linkType: hard "@contentful/content-source-maps@npm:^0.11.0": - version: 0.11.7 - resolution: "@contentful/content-source-maps@npm:0.11.7" + version: 0.11.1 + resolution: "@contentful/content-source-maps@npm:0.11.1" dependencies: "@vercel/stega": "npm:^0.1.2" json-pointer: "npm:^0.6.2" - checksum: 10/7d228f73fc6be3aa2f341fcae7d15cdc60565d81dc9b0770a33f5d50aa729faeb6e33a19c2b8211932119857d06ab858e5e60da9778a5901f06940c7d2ecb78a + checksum: 10/598e88349210aed21c9ee871250353ae15cb4130180ade9cf283261e192a80c72f8674c5533c490ad1358850e45578ed6ed4ac997b32c23b029ae4d096fa5646 languageName: node linkType: hard "@contentful/rich-text-html-renderer@npm:^16.5.2": - version: 16.6.10 - resolution: "@contentful/rich-text-html-renderer@npm:16.6.10" + version: 16.6.9 + resolution: "@contentful/rich-text-html-renderer@npm:16.6.9" dependencies: - "@contentful/rich-text-types": "npm:^16.8.5" + "@contentful/rich-text-types": "npm:^16.8.4" escape-html: "npm:^1.0.3" - checksum: 10/fdf5121524355c96cd8a4628b2cc50a61b9b9d37da167dd983cc8fa24fa822427809d00064ebca9b85b8f40d92719f0b86f0e4ea4eaa8d078656ed56c51df6bb + checksum: 10/10bdcee4c01b89e5ab54ccab592bad7d3658fdd32ee58e2d5d18628a59ca47c7393c8dec41e96172b4c171f7fb4d2d1d6b9da9d6eeebbe5ed83fc3de8c4c0c89 languageName: node linkType: hard -"@contentful/rich-text-types@npm:^16.0.2, @contentful/rich-text-types@npm:^16.8.5": - version: 16.8.5 - resolution: "@contentful/rich-text-types@npm:16.8.5" - checksum: 10/7c1ec7088cc39bbd8f5edc14867ed3d59d06a55f2c92e6c62913aa2312056e920528e6ca6d59780b32c6fe2ab89c429b9f0bce9a52f456be7260f458527ccc3b +"@contentful/rich-text-types@npm:^16.0.2, @contentful/rich-text-types@npm:^16.8.4": + version: 16.8.4 + resolution: "@contentful/rich-text-types@npm:16.8.4" + checksum: 10/22e0a165545f32cc51d1e6231a9e7b617af98c452ecfb28ace9ba8a53b89bb2d940019ffae00ef2bc77c998630a66bfc88d01031e732afb11172f877064aa5b2 languageName: node linkType: hard @@ -706,10 +717,10 @@ __metadata: languageName: node linkType: hard -"@endo/env-options@npm:^1.1.8": - version: 1.1.8 - resolution: "@endo/env-options@npm:1.1.8" - checksum: 10/f7e84346599dd2bcb6365c314e9a8129c5ebbb457476de72ed896ea461d616c0b7e0dfc7733e20c0abb8400212fb5eafdae993bcfd4cbfe92acbb5c881a6ad0d +"@endo/env-options@npm:^1.1.5": + version: 1.1.5 + resolution: "@endo/env-options@npm:1.1.5" + checksum: 10/ce4cb29ecf387f52f7d1c9e7e43b0a1064326587ebac62e7c239bf2df71aa4c3296d2a05cf169d1efcd8c1ddf73aeede8afd86e7b5c9387b80e8e0939d1af0f6 languageName: node linkType: hard @@ -753,12 +764,12 @@ __metadata: languageName: node linkType: hard -"@eslint/core@npm:^0.10.0": - version: 0.10.0 - resolution: "@eslint/core@npm:0.10.0" +"@eslint/core@npm:^0.9.0": + version: 0.9.1 + resolution: "@eslint/core@npm:0.9.1" dependencies: "@types/json-schema": "npm:^7.0.15" - checksum: 10/de41d7fa5dc468b70fb15c72829096939fc0217c41b8519af4620bc1089cb42539a15325c4c3ee3832facac1836c8c944c4a0c4d0cc8b33ffd8e95962278ae14 + checksum: 10/f2263f8f94fdf84fc34573e027de98f1fce6287120513ae672ddf0652c75b9fa77c314d565628fc58e0a6f959766acc34c8191f9b94f1757b910408ffa04adde languageName: node linkType: hard @@ -779,10 +790,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.18.0, @eslint/js@npm:^9.11.0": - version: 9.18.0 - resolution: "@eslint/js@npm:9.18.0" - checksum: 10/364a7d030dad9dbda1458d8dbcea0199fe7d48bcfefe4b49389df6c45cdc5a2449f70e5d8a794e46ed9fb34af3fe5a3f53e30020d306b6ee791e2a1b2b9fa25f +"@eslint/js@npm:9.17.0, @eslint/js@npm:^9.11.0": + version: 9.17.0 + resolution: "@eslint/js@npm:9.17.0" + checksum: 10/1a89e62f5c50e75d44565b7f3b91701455a999132c991e10bac59c118fbb54bdd54be22b9bda1ac730f78a2e64604403d65ce5dd7726d80b2632982cfc3d84ac languageName: node linkType: hard @@ -793,13 +804,12 @@ __metadata: languageName: node linkType: hard -"@eslint/plugin-kit@npm:^0.2.5": - version: 0.2.5 - resolution: "@eslint/plugin-kit@npm:0.2.5" +"@eslint/plugin-kit@npm:^0.2.3": + version: 0.2.4 + resolution: "@eslint/plugin-kit@npm:0.2.4" dependencies: - "@eslint/core": "npm:^0.10.0" levn: "npm:^0.4.1" - checksum: 10/82d0142bc7054587bde4f75c2c517f477df7c320e4bdb47a4d5f766899a313ce65e9ce5d59428178d0be473a95292065053f69637042546b811ad89079781cbc + checksum: 10/e34d02ea1dccd716e51369620263a4b2167aff3c0510ed776e21336cc3ad7158087449a76931baf07cdc33810cb6919db375f2e9f409435d2c6e0dd5f4786b25 languageName: node linkType: hard @@ -1135,18 +1145,25 @@ __metadata: languageName: node linkType: hard -"@firebase/analytics-compat@npm:0.2.14": - version: 0.2.14 - resolution: "@firebase/analytics-compat@npm:0.2.14" +"@fastify/busboy@npm:^2.0.0": + version: 2.1.1 + resolution: "@fastify/busboy@npm:2.1.1" + checksum: 10/2bb8a7eca8289ed14c9eb15239bc1019797454624e769b39a0b90ed204d032403adc0f8ed0d2aef8a18c772205fa7808cf5a1b91f21c7bfc7b6032150b1062c5 + languageName: node + linkType: hard + +"@firebase/analytics-compat@npm:0.2.13": + version: 0.2.13 + resolution: "@firebase/analytics-compat@npm:0.2.13" dependencies: - "@firebase/analytics": "npm:0.10.8" + "@firebase/analytics": "npm:0.10.7" "@firebase/analytics-types": "npm:0.8.2" - "@firebase/component": "npm:0.6.9" - "@firebase/util": "npm:1.10.0" + "@firebase/component": "npm:0.6.8" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/0e368159d24223076b488b27308c11e5ef50456aff49fc58e1f66616228021c61e60c3299f63ce52ddc2f7099d803e9048bc28cd952cf5c302917002c03c85ee + checksum: 10/37af40ac540c68593a118e75c0fc2031459633b46d3fd32f97290fd8c3865fe425cc85feac2243c461924da698e27f4a5c174898e847027b5afd347274080c9c languageName: node linkType: hard @@ -1157,34 +1174,34 @@ __metadata: languageName: node linkType: hard -"@firebase/analytics@npm:0.10.8": - version: 0.10.8 - resolution: "@firebase/analytics@npm:0.10.8" +"@firebase/analytics@npm:0.10.7": + version: 0.10.7 + resolution: "@firebase/analytics@npm:0.10.7" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/installations": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" + "@firebase/installations": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/152ddaf68146f02baa7060d34426c25ec13890a53942ffa2db09faa148bef35f59ee9810e6fb8f561fb3d115b71d1fb9fb111d2a0f0199aa510220782557c765 + checksum: 10/610c67d4ebbd671ace4d0baf2fa7733e1fa97a2f900cb6337b054528a7c98110d861030b2f3c95553ed81253a9cd152edf2b9dc9388a8bec679050bf46674cfe languageName: node linkType: hard -"@firebase/app-check-compat@npm:0.3.15": - version: 0.3.15 - resolution: "@firebase/app-check-compat@npm:0.3.15" +"@firebase/app-check-compat@npm:0.3.14": + version: 0.3.14 + resolution: "@firebase/app-check-compat@npm:0.3.14" dependencies: - "@firebase/app-check": "npm:0.8.8" + "@firebase/app-check": "npm:0.8.7" "@firebase/app-check-types": "npm:0.5.2" - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/ae541d324d5f91dbb7b479855d3380c4fe73e365013b80973a54620405093e6fd2f8e418549155b3a527530472a19b6edf6df1481a708f823eba42e376105b28 + checksum: 10/8d4c835fa95474d556b36ec73f571f3e967cbe590cc76f9964eb9d50905becadf195c5e3cd628fc278efb162529a86a0b5433b72d5d232249168865ab8564392 languageName: node linkType: hard @@ -1202,30 +1219,30 @@ __metadata: languageName: node linkType: hard -"@firebase/app-check@npm:0.8.8": - version: 0.8.8 - resolution: "@firebase/app-check@npm:0.8.8" +"@firebase/app-check@npm:0.8.7": + version: 0.8.7 + resolution: "@firebase/app-check@npm:0.8.7" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/a3676f2143c8e438d7e8ac11bb163af30880f6ce6acc5cc54cfcc214b8efd5dabce14c040626f8a64a3967db144b99834f1108c2076a0eae8a6baf864b5a3d77 + checksum: 10/3f09160bccd99006e33d7bc342dc6c242094be7ffccc6ff0259207006f93f645badb5c1c1743c8a1540d0dab6536a5019eff0ba231b37488ead1209b853287ac languageName: node linkType: hard -"@firebase/app-compat@npm:0.2.43": - version: 0.2.43 - resolution: "@firebase/app-compat@npm:0.2.43" +"@firebase/app-compat@npm:0.2.39": + version: 0.2.39 + resolution: "@firebase/app-compat@npm:0.2.39" dependencies: - "@firebase/app": "npm:0.10.13" - "@firebase/component": "npm:0.6.9" + "@firebase/app": "npm:0.10.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - checksum: 10/e27340dbc9804ffd0d469cc1fa919cd61b6e04fe96599d14414aa06c3dcbe75b23c324f0bedfff4dbd5d9b829b8dde5a2e8b5464f1f686d66f9c00971d9d4c56 + checksum: 10/266a35f349417d8f5ecc69b4d877b0a41e4ef78ddd927fa8f90eb15ea3d709bed7d504b6be49407e2a1e14ad392933be6aff5eb67c2127ab68a00ddb7c26f806 languageName: node linkType: hard @@ -1236,32 +1253,32 @@ __metadata: languageName: node linkType: hard -"@firebase/app@npm:0.10.13": - version: 0.10.13 - resolution: "@firebase/app@npm:0.10.13" +"@firebase/app@npm:0.10.9": + version: 0.10.9 + resolution: "@firebase/app@npm:0.10.9" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" idb: "npm:7.1.1" tslib: "npm:^2.1.0" - checksum: 10/54ec64b3a992c2f30c800fb5638bf586e7e7f351899887c701d5f946ad8ca445d8c1d3024007b7939a7e6ae29a51d90567552a863323594dc6fca22f1e811e0b + checksum: 10/faf344390ce2a857171ca347ca6b81b867b6d4acd87232698c4a93678100c82308796cf906cecad287dadcc83b0a645a22678292b3fb3a97c94cc3ee44c88609 languageName: node linkType: hard -"@firebase/auth-compat@npm:0.5.14": - version: 0.5.14 - resolution: "@firebase/auth-compat@npm:0.5.14" +"@firebase/auth-compat@npm:0.5.12": + version: 0.5.12 + resolution: "@firebase/auth-compat@npm:0.5.12" dependencies: - "@firebase/auth": "npm:1.7.9" + "@firebase/auth": "npm:1.7.7" "@firebase/auth-types": "npm:0.12.2" - "@firebase/component": "npm:0.6.9" - "@firebase/util": "npm:1.10.0" + "@firebase/component": "npm:0.6.8" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - undici: "npm:6.19.7" + undici: "npm:5.28.4" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/85d5259e7b04b14b5d02dc1fb19b015d742c594c14138f33f13146ed9f6caa7ed9d19d65bb99aaca57e70ffd2a491e520d8638eadefbd00f839d37ef972cbbda + checksum: 10/1eeeec3ce7983dbadd1e95cf75e7665486d68eb60b0bc56642412120bdb05d2a389294343532b3cff2114ab8b782c00620ddecf5c194944bfcaead016075a568 languageName: node linkType: hard @@ -1282,101 +1299,86 @@ __metadata: languageName: node linkType: hard -"@firebase/auth@npm:1.7.9": - version: 1.7.9 - resolution: "@firebase/auth@npm:1.7.9" +"@firebase/auth@npm:1.7.7": + version: 1.7.7 + resolution: "@firebase/auth@npm:1.7.7" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - undici: "npm:6.19.7" + undici: "npm:5.28.4" peerDependencies: "@firebase/app": 0.x "@react-native-async-storage/async-storage": ^1.18.1 peerDependenciesMeta: "@react-native-async-storage/async-storage": optional: true - checksum: 10/010013ec339c9ef7b4d9278c6cacfd8e2eb3282f27a3e4e89c42a5968955976a26277421f34fda3e9400409a22a61f632bcc03e713b3f39d71e4777bc003165d - languageName: node - linkType: hard - -"@firebase/component@npm:0.6.9": - version: 0.6.9 - resolution: "@firebase/component@npm:0.6.9" - dependencies: - "@firebase/util": "npm:1.10.0" - tslib: "npm:^2.1.0" - checksum: 10/76c865d640e4b24a0e50876ecdc0e1199df38af562131a937b5a4bac924d61b6933339afb7906881dca509f38f3b0c511cd6b5008e061424c61b20876de9531e + checksum: 10/fe329cdb9cd827cf0c3dd6cba6090496b79bcc09b0e53e685026dc9a1c723310387d4e3655d300ed4789608c7d0fcacbb666c19c4c2be7f416dcc47fb91df0cd languageName: node linkType: hard -"@firebase/data-connect@npm:0.1.0": - version: 0.1.0 - resolution: "@firebase/data-connect@npm:0.1.0" +"@firebase/component@npm:0.6.8": + version: 0.6.8 + resolution: "@firebase/component@npm:0.6.8" dependencies: - "@firebase/auth-interop-types": "npm:0.2.3" - "@firebase/component": "npm:0.6.9" - "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - peerDependencies: - "@firebase/app": 0.x - checksum: 10/20dac7c4755a0dde17abea0c99b41e96c9f7eea6ea39c36fd85f3f5554991b718a25b4bc1f92850208ec1f0e3b1ee584b1cf1913c4ad6c41643655682c06a2b0 + checksum: 10/0df2a61a9d3a32981a82889b4f23923c9adc468e89cadec5984b52d2422bb2b184c1219ed78dc7ec0b7f973ac0b7c2e8f486dee4a32a6741c0627648960e4314 languageName: node linkType: hard -"@firebase/database-compat@npm:1.0.8": - version: 1.0.8 - resolution: "@firebase/database-compat@npm:1.0.8" +"@firebase/database-compat@npm:1.0.7": + version: 1.0.7 + resolution: "@firebase/database-compat@npm:1.0.7" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/database": "npm:1.0.8" - "@firebase/database-types": "npm:1.0.5" + "@firebase/component": "npm:0.6.8" + "@firebase/database": "npm:1.0.7" + "@firebase/database-types": "npm:1.0.4" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - checksum: 10/28389efcc87da77b822cb27c31707824fe98e7b0a3bf9cbf2b0c0fccd9edd72e2681a9467b76b120281464dbfc814852ebca63d99a385a9cb68fb55c7b334105 + checksum: 10/87d6185b65d58784e0c645a8be232f034d7e3bdfbe030b7d88b5597f7d18dc9329a6c6b0eab84f887ab87ef34caf171afc5b97bbd917fa8682015286cb9fcad4 languageName: node linkType: hard -"@firebase/database-types@npm:1.0.5": - version: 1.0.5 - resolution: "@firebase/database-types@npm:1.0.5" +"@firebase/database-types@npm:1.0.4": + version: 1.0.4 + resolution: "@firebase/database-types@npm:1.0.4" dependencies: "@firebase/app-types": "npm:0.9.2" - "@firebase/util": "npm:1.10.0" - checksum: 10/bdf667da0369dce8623987fc01cad8db09cfe1895130f69ab581d34a0ee043ca6113c32457629147ae1441a934d985ede9d7cbe104ac346de6d0c21629903a8b + "@firebase/util": "npm:1.9.7" + checksum: 10/d76125998d322d1fa31a6bf028e21ba03eafb26d7ae3b408ea8f84f52caf1dea716a236a21c64deb857c5eb091ea53cf148b9a2b99f4e97efc5b7c8cabae9acd languageName: node linkType: hard -"@firebase/database@npm:1.0.8": - version: 1.0.8 - resolution: "@firebase/database@npm:1.0.8" +"@firebase/database@npm:1.0.7": + version: 1.0.7 + resolution: "@firebase/database@npm:1.0.7" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" "@firebase/auth-interop-types": "npm:0.2.3" - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" faye-websocket: "npm:0.11.4" tslib: "npm:^2.1.0" - checksum: 10/adb199a6ad7866b418e8b319cc505e108bfc8200b5406f21857706df0849d4e5982a1b0e44e07001821edebef73c4dfffc7f96fb77a2cff10bb9ac26f17d40c3 + checksum: 10/d299c07ac647efb09b644ff91c2aa1d49622c16adc40f75506563aeb8de73f79b17949a13db8089337497e570cebf0df69e8404e934d44a49bb703d05375c245 languageName: node linkType: hard -"@firebase/firestore-compat@npm:0.3.38": - version: 0.3.38 - resolution: "@firebase/firestore-compat@npm:0.3.38" +"@firebase/firestore-compat@npm:0.3.35": + version: 0.3.35 + resolution: "@firebase/firestore-compat@npm:0.3.35" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/firestore": "npm:4.7.3" + "@firebase/component": "npm:0.6.8" + "@firebase/firestore": "npm:4.7.0" "@firebase/firestore-types": "npm:3.0.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/de9e92b5ac612ea73322407b65b1d90067f7138d2159bcfd2400535d09968ea8c8b44956282172129eca78bf951f74a6991394b2634913458927570bb4fa8cd8 + checksum: 10/e3d4cb5cbf555e840eef862cace318d5dc829546c2c7e29d8cabd5ff5d0eb7c756405c4985490c0e1cd524b3dd1ed4e19d4d4a06230e5b6126adac0571010d99 languageName: node linkType: hard @@ -1390,36 +1392,36 @@ __metadata: languageName: node linkType: hard -"@firebase/firestore@npm:4.7.3": - version: 4.7.3 - resolution: "@firebase/firestore@npm:4.7.3" +"@firebase/firestore@npm:4.7.0": + version: 4.7.0 + resolution: "@firebase/firestore@npm:4.7.0" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" "@firebase/webchannel-wrapper": "npm:1.0.1" "@grpc/grpc-js": "npm:~1.9.0" "@grpc/proto-loader": "npm:^0.7.8" tslib: "npm:^2.1.0" - undici: "npm:6.19.7" + undici: "npm:5.28.4" peerDependencies: "@firebase/app": 0.x - checksum: 10/f46a6e3c03eadfa970d8ecc17627d0d696931a19092fcf5be4b2056a209da3691be0bd040a11d333d26c15fd14329ce0fb5dfc32bf2cfa530a4d035b45ef4edf + checksum: 10/b3cb3a62bd3cc5b7ade8689d396d0b0a49821d8709caf787078bbc9306e5d4ddbcb20afbda5138b09934e5fc30ce3561e53419776e7ca454a5025fd195343b12 languageName: node linkType: hard -"@firebase/functions-compat@npm:0.3.14": - version: 0.3.14 - resolution: "@firebase/functions-compat@npm:0.3.14" +"@firebase/functions-compat@npm:0.3.12": + version: 0.3.12 + resolution: "@firebase/functions-compat@npm:0.3.12" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/functions": "npm:0.11.8" + "@firebase/component": "npm:0.6.8" + "@firebase/functions": "npm:0.11.6" "@firebase/functions-types": "npm:0.6.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/a8d6cbcdc646d78adecfcdc1f8fa14a5d9af2394dd69cac00c6826106b923e01d246c67fb7e09025ca7cfb876f8d5df97240cc056c64ccee8899ca5f17178a6c + checksum: 10/d9803c909e848dc381c892d36885a9519b5b025a46afb2c096bf099e840c5c0afc2290b5660a9d763cf6a8bf0ad6f303f85d3011abfc02d75348452bfe3200c8 languageName: node linkType: hard @@ -1430,35 +1432,35 @@ __metadata: languageName: node linkType: hard -"@firebase/functions@npm:0.11.8": - version: 0.11.8 - resolution: "@firebase/functions@npm:0.11.8" +"@firebase/functions@npm:0.11.6": + version: 0.11.6 + resolution: "@firebase/functions@npm:0.11.6" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" "@firebase/auth-interop-types": "npm:0.2.3" - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/messaging-interop-types": "npm:0.2.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - undici: "npm:6.19.7" + undici: "npm:5.28.4" peerDependencies: "@firebase/app": 0.x - checksum: 10/44f3e42df189f3f3cb3c366b38e93a0ffdfaa1a7b3f6dba624bcd9a7cda3d3271df66f2769b7cbe7e1e5ff01bf6ab3bef6c1e1e15c6646e34514d1e2ebb60555 + checksum: 10/c1ac2887dd986c8abc408db1da26531f5f9d252f2cd4ee36352239ed0a0fc11902dd1f85db9ec21818028fd737c5a09461c01c0701c85f9ea96b9dc8dfc69f03 languageName: node linkType: hard -"@firebase/installations-compat@npm:0.2.9": - version: 0.2.9 - resolution: "@firebase/installations-compat@npm:0.2.9" +"@firebase/installations-compat@npm:0.2.8": + version: 0.2.8 + resolution: "@firebase/installations-compat@npm:0.2.8" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/installations": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" + "@firebase/installations": "npm:0.6.8" "@firebase/installations-types": "npm:0.5.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/919e1a4f4b63f5fe757a3c9cefb4a36cbab92deb4a6e15f249c94d6e80d1c6d37e5e384a460af8c17fc88e3091594bf43d036c88b704516c279b5ab8401977e1 + checksum: 10/b0eece054763ac6d229b2fca7ead9cbdd10e6c8429be9f03d95e8ed4a488fcf1cbc3a136f49800b07f2b82fb0f5ff1fecb41bee923aa045314ed854bada256d8 languageName: node linkType: hard @@ -1471,17 +1473,17 @@ __metadata: languageName: node linkType: hard -"@firebase/installations@npm:0.6.9": - version: 0.6.9 - resolution: "@firebase/installations@npm:0.6.9" +"@firebase/installations@npm:0.6.8": + version: 0.6.8 + resolution: "@firebase/installations@npm:0.6.8" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/util": "npm:1.10.0" + "@firebase/component": "npm:0.6.8" + "@firebase/util": "npm:1.9.7" idb: "npm:7.1.1" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/349c8b7e877b002fb29f274f4d239fbca4c2c266ccb66ecfb5f1762f973a7fe1be99cc3346184d1230e6e35feb2b6f9e8b7169479fa0018b53e4a83837848619 + checksum: 10/84cdf30d393fad859f035b276c0ef372cd94907fe042498cdd7c24a719d786866a2f976834b90a49c543e37ae317edd669676830ba7cd83f3a3d34b6f2c0f1ee languageName: node linkType: hard @@ -1494,17 +1496,17 @@ __metadata: languageName: node linkType: hard -"@firebase/messaging-compat@npm:0.2.12": - version: 0.2.12 - resolution: "@firebase/messaging-compat@npm:0.2.12" +"@firebase/messaging-compat@npm:0.2.10": + version: 0.2.10 + resolution: "@firebase/messaging-compat@npm:0.2.10" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/messaging": "npm:0.12.12" - "@firebase/util": "npm:1.10.0" + "@firebase/component": "npm:0.6.8" + "@firebase/messaging": "npm:0.12.10" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/0437ba6b24327d9eb02dc87ba61146fbb9720491ad671dc554438ac87e162d5fb154c704400d55c87ce01dd5aeedada9d0367fd114d840ead0d07802475eaa60 + checksum: 10/3565546cc935f553c0331dc86e593cd39e09c198c549e801dfb9d4ee53152fcc3bab277355bf1a82a063506b8462038dbd3d2122178b9c1edd39c08a0503244d languageName: node linkType: hard @@ -1515,35 +1517,35 @@ __metadata: languageName: node linkType: hard -"@firebase/messaging@npm:0.12.12": - version: 0.12.12 - resolution: "@firebase/messaging@npm:0.12.12" +"@firebase/messaging@npm:0.12.10": + version: 0.12.10 + resolution: "@firebase/messaging@npm:0.12.10" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/installations": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" + "@firebase/installations": "npm:0.6.8" "@firebase/messaging-interop-types": "npm:0.2.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" idb: "npm:7.1.1" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/a00125489085782faf189ad42f75bed108c6632b9d198d114e0a8ce28d89f9455b4f78ff8f7d24d4a86ad13e1e14e0f17fa2ff3605c6dd0c8ff1b65fef23ce3d + checksum: 10/c883b465da2cdee0e08f37119bcb4eb1152bec482fe87136f4dbc6fc9ffbbba1f7c25fff70948844633949ab77bc38d81afd31e7227bf398863cccb878be3095 languageName: node linkType: hard -"@firebase/performance-compat@npm:0.2.9": - version: 0.2.9 - resolution: "@firebase/performance-compat@npm:0.2.9" +"@firebase/performance-compat@npm:0.2.8": + version: 0.2.8 + resolution: "@firebase/performance-compat@npm:0.2.8" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/performance": "npm:0.6.9" + "@firebase/performance": "npm:0.6.8" "@firebase/performance-types": "npm:0.2.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/bc4e8b0208c9bc603518e1388713ec80658ee109c6af80d429479447ccb85e8e831269383233c379ed66bf37469d13f5c234074d0c0c9e7e69e909be5fdeca4f + checksum: 10/354a31f31c0d07df10a2b33f4ef2b34ba931cb51738c533c5af9e85c1645d9421f2262ec72eb54a3821f1df52644254f92b866d836c528d6a8ff91b399a2aad4 languageName: node linkType: hard @@ -1554,34 +1556,34 @@ __metadata: languageName: node linkType: hard -"@firebase/performance@npm:0.6.9": - version: 0.6.9 - resolution: "@firebase/performance@npm:0.6.9" +"@firebase/performance@npm:0.6.8": + version: 0.6.8 + resolution: "@firebase/performance@npm:0.6.8" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/installations": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" + "@firebase/installations": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/d682d0b1e342ed3eda1a5ddab39c8ddac33afc9edb2c7335a2f9a28eb8c268b975bbf450a3bad5443138edebaf2aa731dca0b774bcf3211a6dc215b35d86d849 + checksum: 10/5c989d154daea84f009f221245231bf5050cf0d96688bf1b20add98429088c815cc6e76e91180394c9d7fe5759094bbe4261c13604ff349c67e3d7113959b146 languageName: node linkType: hard -"@firebase/remote-config-compat@npm:0.2.9": - version: 0.2.9 - resolution: "@firebase/remote-config-compat@npm:0.2.9" +"@firebase/remote-config-compat@npm:0.2.8": + version: 0.2.8 + resolution: "@firebase/remote-config-compat@npm:0.2.8" dependencies: - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/remote-config": "npm:0.4.9" + "@firebase/remote-config": "npm:0.4.8" "@firebase/remote-config-types": "npm:0.3.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/a6db7509512d8d22b7ddf1127c741715e379e04e5b3246372bb0302d7c84afb421a94550adebecddcce5def115d61729a9580940dce6e65f8d77f9af30f69fe1 + checksum: 10/342b27720635c7f68ce8953cd22a5badfc628c3fb9414b32d40a2eaacb2feb2068079eac15c3c811f4327a06d01aa71631a6f2cfe8b80460f1910cfd37126342 languageName: node linkType: hard @@ -1592,33 +1594,33 @@ __metadata: languageName: node linkType: hard -"@firebase/remote-config@npm:0.4.9": - version: 0.4.9 - resolution: "@firebase/remote-config@npm:0.4.9" +"@firebase/remote-config@npm:0.4.8": + version: 0.4.8 + resolution: "@firebase/remote-config@npm:0.4.8" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/installations": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" + "@firebase/installations": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x - checksum: 10/f14189f38c8cf75db16bf8b85dd004486b1dd8242f62d697c716fa85cd32928aed549ccea8c632a528870a424fc7f04f1132a14b3b099276cd7696c78e644b28 + checksum: 10/58f934b8cdc8582f260a8caf5b903d484d74aecba420221bf57e5df28f8ba7d3f9ca1ab58946c90ab2c29659bbfdad679fc59247468068063a5329d92cd27613 languageName: node linkType: hard -"@firebase/storage-compat@npm:0.3.12": - version: 0.3.12 - resolution: "@firebase/storage-compat@npm:0.3.12" +"@firebase/storage-compat@npm:0.3.10": + version: 0.3.10 + resolution: "@firebase/storage-compat@npm:0.3.10" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/storage": "npm:0.13.2" + "@firebase/component": "npm:0.6.8" + "@firebase/storage": "npm:0.13.0" "@firebase/storage-types": "npm:0.8.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app-compat": 0.x - checksum: 10/4eea49a57f1d7537da697e5ff8b4e035ff1af69e416e7eab14485753c39c25eaa5a71bd2bafba0985ac6a7ce803f98f2f2f83c613c78c8f74bce286e3259b8ec + checksum: 10/63486c25c9b241ad5a55d9ab0a448ee9fc6a53b39733709ea56bce26e32cbdd1e8d4a22601a233ee18734ba1111a7ee52ca0196c281d0f4a88061a555306efb1 languageName: node linkType: hard @@ -1632,42 +1634,42 @@ __metadata: languageName: node linkType: hard -"@firebase/storage@npm:0.13.2": - version: 0.13.2 - resolution: "@firebase/storage@npm:0.13.2" +"@firebase/storage@npm:0.13.0": + version: 0.13.0 + resolution: "@firebase/storage@npm:0.13.0" dependencies: - "@firebase/component": "npm:0.6.9" - "@firebase/util": "npm:1.10.0" + "@firebase/component": "npm:0.6.8" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" - undici: "npm:6.19.7" + undici: "npm:5.28.4" peerDependencies: "@firebase/app": 0.x - checksum: 10/d887f80cf95ef5daa80ffb2e6d564d25abb8a3e84099bee9730c95082597a12028bbf73bfe66fca2df3cdf04eaadea8e9d74ec0a826f946bc8f002293a9983ea + checksum: 10/b33708f14ccb4aa7755a1e4dea3ce483aec0bd077bb9db8df4238f4c96f80e39ef687940ece39c3fa7dcceb0f6e5f3a22874f19dc8d05246226d4c1637508158 languageName: node linkType: hard -"@firebase/util@npm:1.10.0": - version: 1.10.0 - resolution: "@firebase/util@npm:1.10.0" +"@firebase/util@npm:1.9.7": + version: 1.9.7 + resolution: "@firebase/util@npm:1.9.7" dependencies: tslib: "npm:^2.1.0" - checksum: 10/eb161f1c6294ff097f3c40236820e9e6e29cd6582e5e1254148157143272493580535ee2cb9e7c6055d3909b3ef39d8b64086895b071c665827acb66742b63eb + checksum: 10/c31290f45794af68a3ab571db1c0e3cb4d15443adfdc50107b835274b4ad525f839ee79a0da2898dd8b31e64ff811c126d338b0bab117be59c0a065ce984a89a languageName: node linkType: hard -"@firebase/vertexai-preview@npm:0.0.4": - version: 0.0.4 - resolution: "@firebase/vertexai-preview@npm:0.0.4" +"@firebase/vertexai-preview@npm:0.0.3": + version: 0.0.3 + resolution: "@firebase/vertexai-preview@npm:0.0.3" dependencies: "@firebase/app-check-interop-types": "npm:0.3.2" - "@firebase/component": "npm:0.6.9" + "@firebase/component": "npm:0.6.8" "@firebase/logger": "npm:0.4.2" - "@firebase/util": "npm:1.10.0" + "@firebase/util": "npm:1.9.7" tslib: "npm:^2.1.0" peerDependencies: "@firebase/app": 0.x "@firebase/app-types": 0.x - checksum: 10/8ec48d81f48aebdcc63b65d802c67bf36880f256e5c2f5f3b152dc91c8c0e924053fba2fac5218716612f8ee720b25d0822337a214f16f5b7e51ce0247dfc4e5 + checksum: 10/490ea78f153b764e117989cb0ee9abeb0f456c6daefc58aa949147b1404a2d90d49c84a04556f8d84a729692ca99ed670b9dd9b37169b93ac01dc8d9242dac13 languageName: node linkType: hard @@ -1792,15 +1794,6 @@ __metadata: languageName: node linkType: hard -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10/4412e9e6713c89c1e66d80bb0bb5a2a93192f10477623a27d08f228ba0316bb880affabc5bfe7f838f58a34d26c2c190da726e576cdfc18c49a72e89adabdcf5 - languageName: node - linkType: hard - "@istanbuljs/load-nyc-config@npm:^1.0.0": version: 1.1.0 resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" @@ -2091,13 +2084,13 @@ __metadata: linkType: hard "@jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.8 - resolution: "@jridgewell/gen-mapping@npm:0.3.8" + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" dependencies: "@jridgewell/set-array": "npm:^1.2.1" "@jridgewell/sourcemap-codec": "npm:^1.4.10" "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/9d3a56ab3612ab9b85d38b2a93b87f3324f11c5130859957f6500e4ac8ce35f299d5ccc3ecd1ae87597601ecf83cee29e9afd04c18777c24011073992ff946df + checksum: 10/81587b3c4dd8e6c60252122937cea0c637486311f4ed208b52b62aae2e7a87598f63ec330e6cd0984af494bfb16d3f0d60d3b21d7e5b4aedd2602ff3fe9d32e2 languageName: node linkType: hard @@ -2249,32 +2242,31 @@ __metadata: languageName: node linkType: hard -"@lavamoat/aa@npm:^4.3.1": - version: 4.3.1 - resolution: "@lavamoat/aa@npm:4.3.1" +"@lavamoat/aa@npm:^4.3.0": + version: 4.3.0 + resolution: "@lavamoat/aa@npm:4.3.0" dependencies: resolve: "npm:1.22.8" bin: lavamoat-ls: src/cli.js - checksum: 10/664692b22c6fcf44a47259ec3b48873c0064872a5a285c7ee4ddc0f99217d5a6653236304cc393f03970f0810694ab44d1f02ce4c980ce86cc24b0e27e9c622f + checksum: 10/c6c24ea88194ad06a83cc2a9e0b6918ee41ab40abcc5c889e1a33f214e48eb160dd0c4cea7b0e299f86d472810ef80e7caf0b2600499222b108690516d9f8123 languageName: node linkType: hard "@lavamoat/allow-scripts@npm:^3.0.4": - version: 3.3.1 - resolution: "@lavamoat/allow-scripts@npm:3.3.1" + version: 3.2.0 + resolution: "@lavamoat/allow-scripts@npm:3.2.0" dependencies: - "@lavamoat/aa": "npm:^4.3.1" + "@lavamoat/aa": "npm:^4.3.0" "@npmcli/run-script": "npm:8.1.0" bin-links: "npm:4.0.4" npm-normalize-package-bin: "npm:3.0.1" - type-fest: "npm:4.30.0" yargs: "npm:17.7.2" peerDependencies: "@lavamoat/preinstall-always-fail": "*" bin: allow-scripts: src/cli.js - checksum: 10/78bb7502136cee509592e66a1824a3e049a392e79740d99f528774743934d28e2099d3e80beded9a6623ce8842250d6207ebeea694d08c87e4fd8e2899eb0d7a + checksum: 10/21afb11ce25c0b2c9763bfb8f1127bb89f304ed83f64e00955c4d3007216a0ee553b777359e9ded874c61b3d7fa8d19ff8a35881cd3816985adab4d6b58bcb07 languageName: node linkType: hard @@ -2387,13 +2379,13 @@ __metadata: linkType: soft "@metamask/api-specs@npm:^0.10.12": - version: 0.10.13 - resolution: "@metamask/api-specs@npm:0.10.13" - checksum: 10/c3a4d61a4fa5a610ee8c7bec68852d8a301e9003493ae3a37e475329cf1d37036746f3d9417026e13670eafc848895ff6274fe12472d34338f344d2f80c32d8d + version: 0.10.12 + resolution: "@metamask/api-specs@npm:0.10.12" + checksum: 10/e592f27f350994688d3d54a8a8db16de033011ef665efe3283a77431914d8d69d1c3312fad33e4245b4984e1223b04c98da3d0a68c7f9577cf8290ba441c52ee languageName: node linkType: hard -"@metamask/approval-controller@npm:^7.1.2, @metamask/approval-controller@workspace:packages/approval-controller": +"@metamask/approval-controller@npm:^7.1.1, @metamask/approval-controller@npm:^7.1.2, @metamask/approval-controller@workspace:packages/approval-controller": version: 0.0.0-use.local resolution: "@metamask/approval-controller@workspace:packages/approval-controller" dependencies: @@ -2513,7 +2505,7 @@ __metadata: languageName: node linkType: hard -"@metamask/base-controller@npm:^7.0.3, @metamask/base-controller@npm:^7.1.1, @metamask/base-controller@workspace:packages/base-controller": +"@metamask/base-controller@npm:^7.0.2, @metamask/base-controller@npm:^7.1.1, @metamask/base-controller@workspace:packages/base-controller": version: 0.0.0-use.local resolution: "@metamask/base-controller@workspace:packages/base-controller" dependencies: @@ -2783,16 +2775,16 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-block-tracker@npm:^11.0.3, @metamask/eth-block-tracker@npm:^11.0.4": - version: 11.0.4 - resolution: "@metamask/eth-block-tracker@npm:11.0.4" +"@metamask/eth-block-tracker@npm:^11.0.3": + version: 11.0.3 + resolution: "@metamask/eth-block-tracker@npm:11.0.3" dependencies: "@metamask/eth-json-rpc-provider": "npm:^4.1.5" "@metamask/safe-event-emitter": "npm:^3.1.1" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^9.1.0" json-rpc-random-id: "npm:^1.0.1" pify: "npm:^5.0.0" - checksum: 10/56b60255a3ae23a378570a49c30d0c13bd74094c0509a978cad20ef57079c80bae91fd35749acb9ac5feef2922eec45a6fef8c0ee6e754cbf3722f8e5d0d771e + checksum: 10/c73a570f889c613ab309643c84a4aed1a4eeed5c101434da84b34babe2352218c65f863602e013a8a55052e3f80a538efed865cc5fb7af558d168c52c5a399a4 languageName: node linkType: hard @@ -2835,21 +2827,21 @@ __metadata: linkType: hard "@metamask/eth-json-rpc-middleware@npm:^15.0.1": - version: 15.1.2 - resolution: "@metamask/eth-json-rpc-middleware@npm:15.1.2" + version: 15.0.1 + resolution: "@metamask/eth-json-rpc-middleware@npm:15.0.1" dependencies: - "@metamask/eth-block-tracker": "npm:^11.0.4" - "@metamask/eth-json-rpc-provider": "npm:^4.1.7" - "@metamask/eth-sig-util": "npm:^8.1.2" - "@metamask/json-rpc-engine": "npm:^10.0.2" - "@metamask/rpc-errors": "npm:^7.0.2" - "@metamask/utils": "npm:^11.0.1" + "@metamask/eth-block-tracker": "npm:^11.0.3" + "@metamask/eth-json-rpc-provider": "npm:^4.1.5" + "@metamask/eth-sig-util": "npm:^7.0.3" + "@metamask/json-rpc-engine": "npm:^10.0.0" + "@metamask/rpc-errors": "npm:^7.0.0" + "@metamask/utils": "npm:^9.1.0" "@types/bn.js": "npm:^5.1.5" bn.js: "npm:^5.2.1" klona: "npm:^2.0.6" pify: "npm:^5.0.0" safe-stable-stringify: "npm:^2.4.3" - checksum: 10/71e7d61cc58df250bfef73438a9e30cc2f78e0e979feb8a9c0be72bbad470a2fe068fa790194cb88ef56865e36156e525272bc3e1a2a7135d07f7bd81a752239 + checksum: 10/9777fca31440bf0076f5d2c24e2ddb4848ecd9d41b0a5d6114c27339567e60bfcb9057d6bfa81f18f5ca0ffa848ecf9603c765f606b8de206d3e34dba519c501 languageName: node linkType: hard @@ -3150,7 +3142,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/json-rpc-engine@npm:^10.0.0, @metamask/json-rpc-engine@npm:^10.0.2, @metamask/json-rpc-engine@workspace:packages/json-rpc-engine": +"@metamask/json-rpc-engine@npm:^10.0.0, @metamask/json-rpc-engine@npm:^10.0.1, @metamask/json-rpc-engine@npm:^10.0.2, @metamask/json-rpc-engine@workspace:packages/json-rpc-engine": version: 0.0.0-use.local resolution: "@metamask/json-rpc-engine@workspace:packages/json-rpc-engine" dependencies: @@ -3170,7 +3162,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/json-rpc-middleware-stream@npm:^8.0.6, @metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream": +"@metamask/json-rpc-middleware-stream@npm:^8.0.5, @metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream": version: 0.0.0-use.local resolution: "@metamask/json-rpc-middleware-stream@workspace:packages/json-rpc-middleware-stream" dependencies: @@ -3193,16 +3185,16 @@ __metadata: languageName: unknown linkType: soft -"@metamask/key-tree@npm:^10.0.2": - version: 10.0.2 - resolution: "@metamask/key-tree@npm:10.0.2" +"@metamask/key-tree@npm:^9.1.2": + version: 9.1.2 + resolution: "@metamask/key-tree@npm:9.1.2" dependencies: "@metamask/scure-bip39": "npm:^2.1.1" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^9.0.0" "@noble/curves": "npm:^1.2.0" "@noble/hashes": "npm:^1.3.2" "@scure/base": "npm:^1.0.0" - checksum: 10/fd2e445c75dc3cd3976fdc38a5029ee71a6f4afcbbf5c9a17152bba70cf35df8095caa853ae62eef90a51b43f23eeb9546fc6eb7d93a099d82effe8dc7592259 + checksum: 10/9b178a4156b2f36bf630564dd0530c41c6356492971d2bcc8f979c79c81144945823a5b770e4097e12b89b42133b81f00c95a7b8fe9931ea1dd928989ee3c406 languageName: node linkType: hard @@ -3449,14 +3441,14 @@ __metadata: linkType: soft "@metamask/nonce-tracker@npm:^6.0.0": - version: 6.0.1 - resolution: "@metamask/nonce-tracker@npm:6.0.1" + version: 6.0.0 + resolution: "@metamask/nonce-tracker@npm:6.0.0" dependencies: "@ethersproject/providers": "npm:^5.7.2" - async-mutex: "npm:^0.5.0" + async-mutex: "npm:^0.3.1" peerDependencies: "@metamask/eth-block-tracker": ">=9" - checksum: 10/3f0ba80be867e210dbde4b3cfef7d3b458217a2b744731efb9500c6223910c08e301c1d2c69a2502b0bf396ddd6bf5328d525acafb3613756aa1ae658948ec25 + checksum: 10/e62edd38eeaba6d917bc3aed38017294f2bfdb59120a9fb4f093fe96a46d8d9214453a802fe782faaf4a007f4cd5f393607c70a2ff8479ecd7ef18827cad067a languageName: node linkType: hard @@ -3504,27 +3496,27 @@ __metadata: languageName: node linkType: hard -"@metamask/object-multiplex@npm:^2.0.0, @metamask/object-multiplex@npm:^2.1.0": - version: 2.1.0 - resolution: "@metamask/object-multiplex@npm:2.1.0" +"@metamask/object-multiplex@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/object-multiplex@npm:2.0.0" dependencies: once: "npm:^1.4.0" readable-stream: "npm:^3.6.2" - checksum: 10/e119f695e89eb20c3174f8ac6d74587498d85cff92c37e83e167cb758b3d3147d5b5e1a997d6198d430ebcf2cede6265bf5d4513fe96dbb2d82bbc6167752caa + checksum: 10/54baea752a3ac7c2742c376512e00d4902d383e9da8787574d3b21eb0081523309e24e3915a98f3ae0341d65712b6832d2eb7eeb862f4ef0da1ead52dcde5387 languageName: node linkType: hard "@metamask/obs-store@npm:^9.0.0": - version: 9.1.0 - resolution: "@metamask/obs-store@npm:9.1.0" + version: 9.0.0 + resolution: "@metamask/obs-store@npm:9.0.0" dependencies: "@metamask/safe-event-emitter": "npm:^3.0.0" readable-stream: "npm:^3.6.2" - checksum: 10/fa37a0b9e1e25f54c93a8f16449b3fc771c15b70d79d590cf41e22f871a19d673bcfd0d08b044093235d10d0bb031b47b8209d89997def0cb256abe3e371064f + checksum: 10/1c202a5bbdc79a6b8b3fba946c09dc5521e87260956d30db6543e7bf3d95bd44ebd958f509e3e7332041845176487fe78d3b40bdedbc213061ba849fd978e468 languageName: node linkType: hard -"@metamask/permission-controller@npm:^11.0.5, @metamask/permission-controller@workspace:packages/permission-controller": +"@metamask/permission-controller@npm:^11.0.3, @metamask/permission-controller@npm:^11.0.5, @metamask/permission-controller@workspace:packages/permission-controller": version: 0.0.0-use.local resolution: "@metamask/permission-controller@workspace:packages/permission-controller" dependencies: @@ -3572,7 +3564,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/phishing-controller@npm:^12.3.1, @metamask/phishing-controller@workspace:packages/phishing-controller": +"@metamask/phishing-controller@npm:^12.0.2, @metamask/phishing-controller@workspace:packages/phishing-controller": version: 0.0.0-use.local resolution: "@metamask/phishing-controller@workspace:packages/phishing-controller" dependencies: @@ -3621,13 +3613,13 @@ __metadata: languageName: unknown linkType: soft -"@metamask/post-message-stream@npm:^9.0.0": - version: 9.0.0 - resolution: "@metamask/post-message-stream@npm:9.0.0" +"@metamask/post-message-stream@npm:^8.1.1": + version: 8.1.1 + resolution: "@metamask/post-message-stream@npm:8.1.1" dependencies: - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^9.0.0" readable-stream: "npm:3.6.2" - checksum: 10/5da711d3274e724452322939a5a77c60ed1d7ed73cdaa62e95c16debc443804d5a16de116dce742e05b3fbfa962e009dfeafc3a12a66f20e163617567f2cace5 + checksum: 10/8218d321abe734522aefaf6b44e4203966c3feaf83e2de6e68eef9dbe92b7fb47fe7fd82eae362147b1d741cc58d78bcc95d8bf02058e260ad2fb978104c96cf languageName: node linkType: hard @@ -3695,16 +3687,16 @@ __metadata: languageName: unknown linkType: soft -"@metamask/providers@npm:^18.1.1, @metamask/providers@npm:^18.3.1": - version: 18.3.1 - resolution: "@metamask/providers@npm:18.3.1" +"@metamask/providers@npm:^18.1.1": + version: 18.1.1 + resolution: "@metamask/providers@npm:18.1.1" dependencies: - "@metamask/json-rpc-engine": "npm:^10.0.2" - "@metamask/json-rpc-middleware-stream": "npm:^8.0.6" + "@metamask/json-rpc-engine": "npm:^10.0.1" + "@metamask/json-rpc-middleware-stream": "npm:^8.0.5" "@metamask/object-multiplex": "npm:^2.0.0" - "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/rpc-errors": "npm:^7.0.1" "@metamask/safe-event-emitter": "npm:^3.1.1" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^10.0.0" detect-browser: "npm:^5.2.0" extension-port-stream: "npm:^4.1.0" fast-deep-equal: "npm:^3.1.3" @@ -3712,7 +3704,7 @@ __metadata: readable-stream: "npm:^3.6.2" peerDependencies: webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 - checksum: 10/0e21ba9cce926a49dedbfe30fc964cd2349ee6bf9156f525fb894dcbc147a3ae480384884131a6b1a0a508989b547d8c8d2aeb3d10e11f67a8ee5230c45631a8 + checksum: 10/dca428d84e490343d85921d4fb09216a0b64be59a036d7b4f7b5ca4e2581c29a4106d58ff9dfe0650dc2b9387dd2adad508fc61073a9fda8ebde8ee3a5137abe languageName: node linkType: hard @@ -3786,7 +3778,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/rpc-errors@npm:^7.0.0, @metamask/rpc-errors@npm:^7.0.2": +"@metamask/rpc-errors@npm:^7.0.0, @metamask/rpc-errors@npm:^7.0.1, @metamask/rpc-errors@npm:^7.0.2": version: 7.0.2 resolution: "@metamask/rpc-errors@npm:7.0.2" dependencies: @@ -3797,9 +3789,9 @@ __metadata: linkType: hard "@metamask/safe-event-emitter@npm:^3.0.0, @metamask/safe-event-emitter@npm:^3.1.1": - version: 3.1.2 - resolution: "@metamask/safe-event-emitter@npm:3.1.2" - checksum: 10/8ef7579f9317eb5c94ecf3e6abb8d13b119af274b678805eac76abe4c0667bfdf539f385e552bb973e96333b71b77aa7c787cb3fce9cd5fb4b00f1dbbabf880d + version: 3.1.1 + resolution: "@metamask/safe-event-emitter@npm:3.1.1" + checksum: 10/e24db4d7c20764bfc5b025065f92518c805f0ffb1da4820078b8cff7dcae964c0f354cf053fcb7ac659de015d5ffdf21aae5e8d44e191ee8faa9066855f22653 languageName: node linkType: hard @@ -3872,111 +3864,107 @@ __metadata: languageName: unknown linkType: soft -"@metamask/slip44@npm:^4.1.0": - version: 4.1.0 - resolution: "@metamask/slip44@npm:4.1.0" - checksum: 10/4265254a1800a24915bd1de15f86f196737132f9af2a084c2efc885decfc5dd87ad8f0687269d90b35e2ec64d3ea4fbff0caa793bcea6e585b1f3a290952b750 +"@metamask/slip44@npm:^4.0.0": + version: 4.0.0 + resolution: "@metamask/slip44@npm:4.0.0" + checksum: 10/3e47e8834b0fbdabe1f126fd78665767847ddc1f9ccc8defb23007dd71fcd2e4899c8ca04857491be3630668a3765bad1e40fdfca9a61ef33236d8d08e51535e languageName: node linkType: hard "@metamask/snaps-controllers@npm:^9.10.0": - version: 9.17.0 - resolution: "@metamask/snaps-controllers@npm:9.17.0" + version: 9.13.0 + resolution: "@metamask/snaps-controllers@npm:9.13.0" dependencies: - "@metamask/approval-controller": "npm:^7.1.2" - "@metamask/base-controller": "npm:^7.0.3" - "@metamask/json-rpc-engine": "npm:^10.0.2" - "@metamask/json-rpc-middleware-stream": "npm:^8.0.6" - "@metamask/key-tree": "npm:^10.0.2" - "@metamask/object-multiplex": "npm:^2.1.0" - "@metamask/permission-controller": "npm:^11.0.5" - "@metamask/phishing-controller": "npm:^12.3.1" - "@metamask/post-message-stream": "npm:^9.0.0" - "@metamask/rpc-errors": "npm:^7.0.2" - "@metamask/snaps-registry": "npm:^3.2.3" - "@metamask/snaps-rpc-methods": "npm:^11.9.0" - "@metamask/snaps-sdk": "npm:^6.15.0" - "@metamask/snaps-utils": "npm:^8.8.0" - "@metamask/utils": "npm:^11.0.1" + "@metamask/approval-controller": "npm:^7.1.1" + "@metamask/base-controller": "npm:^7.0.2" + "@metamask/json-rpc-engine": "npm:^10.0.1" + "@metamask/json-rpc-middleware-stream": "npm:^8.0.5" + "@metamask/object-multiplex": "npm:^2.0.0" + "@metamask/permission-controller": "npm:^11.0.3" + "@metamask/phishing-controller": "npm:^12.0.2" + "@metamask/post-message-stream": "npm:^8.1.1" + "@metamask/rpc-errors": "npm:^7.0.1" + "@metamask/snaps-registry": "npm:^3.2.2" + "@metamask/snaps-rpc-methods": "npm:^11.5.1" + "@metamask/snaps-sdk": "npm:^6.11.0" + "@metamask/snaps-utils": "npm:^8.6.0" + "@metamask/utils": "npm:^10.0.0" "@xstate/fsm": "npm:^2.0.0" - async-mutex: "npm:^0.5.0" browserify-zlib: "npm:^0.2.0" concat-stream: "npm:^2.0.0" fast-deep-equal: "npm:^3.1.3" get-npm-tarball-url: "npm:^2.0.3" immer: "npm:^9.0.6" - luxon: "npm:^3.5.0" nanoid: "npm:^3.1.31" readable-stream: "npm:^3.6.2" readable-web-to-node-stream: "npm:^3.0.2" semver: "npm:^7.5.4" tar-stream: "npm:^3.1.7" peerDependencies: - "@metamask/snaps-execution-environments": ^6.12.0 + "@metamask/snaps-execution-environments": ^6.10.0 peerDependenciesMeta: "@metamask/snaps-execution-environments": optional: true - checksum: 10/c09eb4a31e685a9fbe41f2b407d9037785e572a7ef135ecfbede3cf015eaa87bef53c17e615a85ad8bbb757d8baf969cd14766dc70c04aa7645ef819ef03417d + checksum: 10/bcf60b61de067f89439cb15acbdf6f808b4bcda8e1cbc9debd693ca2c545c9d38c4e6f380191c4703bd9d28d7dd41e4ce5111664d7b474d5e86e460bcefc3637 languageName: node linkType: hard -"@metamask/snaps-registry@npm:^3.2.3": - version: 3.2.3 - resolution: "@metamask/snaps-registry@npm:3.2.3" +"@metamask/snaps-registry@npm:^3.2.2": + version: 3.2.2 + resolution: "@metamask/snaps-registry@npm:3.2.2" dependencies: "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^10.0.0" "@noble/curves": "npm:^1.2.0" "@noble/hashes": "npm:^1.3.2" - checksum: 10/37760f29b7aaa337d815cf0c11fa34af5093d87fdc60a3750c494cf8bae6293cd52da03e7694b467b79733052d75ec6e3781ab3590d7259a050784e5be347d12 + checksum: 10/ca8239e838bbb913435e166136bbc9bd7222c4bd87b1525fa7ae3cdf2e0b868b5d4d90a67d1ed49633d566bdef9243abdbf5f5937b85a85d24184087f555813e languageName: node linkType: hard -"@metamask/snaps-rpc-methods@npm:^11.9.0": - version: 11.9.0 - resolution: "@metamask/snaps-rpc-methods@npm:11.9.0" +"@metamask/snaps-rpc-methods@npm:^11.5.1": + version: 11.5.1 + resolution: "@metamask/snaps-rpc-methods@npm:11.5.1" dependencies: - "@metamask/key-tree": "npm:^10.0.2" - "@metamask/permission-controller": "npm:^11.0.5" - "@metamask/rpc-errors": "npm:^7.0.2" - "@metamask/snaps-sdk": "npm:^6.15.0" - "@metamask/snaps-utils": "npm:^8.8.0" + "@metamask/key-tree": "npm:^9.1.2" + "@metamask/permission-controller": "npm:^11.0.3" + "@metamask/rpc-errors": "npm:^7.0.1" + "@metamask/snaps-sdk": "npm:^6.10.0" + "@metamask/snaps-utils": "npm:^8.5.0" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^10.0.0" "@noble/hashes": "npm:^1.3.1" - luxon: "npm:^3.5.0" - checksum: 10/44d47d3d8dcaa349863f2df2622c6fedc15e56e77d00ee97caadf3cebef6ddca06c8d4fa199b196a067bbdce59ec9a867446c133658b098216746bc23e7245f8 + checksum: 10/0f999a5dd64f1b1123366f448ae833f0e95a415791600bb535959ba67d2269fbe3c4504d47f04db71bafa79a9a87d6b832fb2e2b5ef29567078c95bce2638f35 languageName: node linkType: hard -"@metamask/snaps-sdk@npm:^6.15.0, @metamask/snaps-sdk@npm:^6.7.0": - version: 6.15.0 - resolution: "@metamask/snaps-sdk@npm:6.15.0" +"@metamask/snaps-sdk@npm:^6.10.0, @metamask/snaps-sdk@npm:^6.11.0, @metamask/snaps-sdk@npm:^6.7.0": + version: 6.11.0 + resolution: "@metamask/snaps-sdk@npm:6.11.0" dependencies: - "@metamask/key-tree": "npm:^10.0.2" - "@metamask/providers": "npm:^18.3.1" - "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/key-tree": "npm:^9.1.2" + "@metamask/providers": "npm:^18.1.1" + "@metamask/rpc-errors": "npm:^7.0.1" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^11.0.1" - checksum: 10/0e561a0b3ae96521efbdb7223a46e42a634f84a61f271288b5c549ccc2a974247100925d551b359bd84d76aec75529dff726176e5379f446721c48f702cf2598 + "@metamask/utils": "npm:^10.0.0" + checksum: 10/0f9b507139d1544b1b3d85ff8de81b800d543012d3ee9414c607c23abe9562e0dca48de089ed94be69f5ad981730a0f443371edfe6bc2d5ffb140b28e437bfd2 languageName: node linkType: hard -"@metamask/snaps-utils@npm:^8.3.0, @metamask/snaps-utils@npm:^8.8.0": - version: 8.8.0 - resolution: "@metamask/snaps-utils@npm:8.8.0" +"@metamask/snaps-utils@npm:^8.3.0, @metamask/snaps-utils@npm:^8.5.0, @metamask/snaps-utils@npm:^8.6.0": + version: 8.6.0 + resolution: "@metamask/snaps-utils@npm:8.6.0" dependencies: "@babel/core": "npm:^7.23.2" "@babel/types": "npm:^7.23.0" - "@metamask/base-controller": "npm:^7.0.3" - "@metamask/key-tree": "npm:^10.0.2" - "@metamask/permission-controller": "npm:^11.0.5" - "@metamask/rpc-errors": "npm:^7.0.2" - "@metamask/slip44": "npm:^4.1.0" - "@metamask/snaps-registry": "npm:^3.2.3" - "@metamask/snaps-sdk": "npm:^6.15.0" + "@metamask/base-controller": "npm:^7.0.2" + "@metamask/key-tree": "npm:^9.1.2" + "@metamask/permission-controller": "npm:^11.0.3" + "@metamask/rpc-errors": "npm:^7.0.1" + "@metamask/slip44": "npm:^4.0.0" + "@metamask/snaps-registry": "npm:^3.2.2" + "@metamask/snaps-sdk": "npm:^6.11.0" "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^11.0.1" + "@metamask/utils": "npm:^10.0.0" "@noble/hashes": "npm:^1.3.1" "@scure/base": "npm:^1.1.1" chalk: "npm:^4.1.2" @@ -3989,7 +3977,7 @@ __metadata: semver: "npm:^7.5.4" ses: "npm:^1.1.0" validate-npm-package-name: "npm:^5.0.0" - checksum: 10/567354cf09dc74fe392e281e836325bfec570428dd77101935fa443bcc987bfdee6a568a572b92269639fda30a7f02ff1047ad887aed52b73709ab7a6bf1cddd + checksum: 10/c0f538f3f95e1875f6557b6ecc32f981bc4688d581af8cdc62c6c3ab8951c138286cd0b2d1cd82f769df24fcec10f71dcda67ae9a47edcff9ff73d52672df191 languageName: node linkType: hard @@ -4100,6 +4088,23 @@ __metadata: languageName: unknown linkType: soft +"@metamask/utils@npm:^10.0.0": + version: 10.0.0 + resolution: "@metamask/utils@npm:10.0.0" + dependencies: + "@ethereumjs/tx": "npm:^4.2.0" + "@metamask/superstruct": "npm:^3.1.0" + "@noble/hashes": "npm:^1.3.1" + "@scure/base": "npm:^1.1.3" + "@types/debug": "npm:^4.1.7" + debug: "npm:^4.3.4" + pony-cause: "npm:^2.1.10" + semver: "npm:^7.5.4" + uuid: "npm:^9.0.1" + checksum: 10/9c2e6421f685d8a45145b6026a6f9fd0701eb5a2e8490fc6d18e64c103d5a62097f301cbc797790da52ceb5853bd9f65845c934b00299e69e5e6736c52b32f0f + languageName: node + linkType: hard + "@metamask/utils@npm:^11.0.1": version: 11.0.1 resolution: "@metamask/utils@npm:11.0.1" @@ -4192,11 +4197,11 @@ __metadata: linkType: hard "@noble/curves@npm:^1.2.0": - version: 1.8.0 - resolution: "@noble/curves@npm:1.8.0" + version: 1.5.0 + resolution: "@noble/curves@npm:1.5.0" dependencies: - "@noble/hashes": "npm:1.7.0" - checksum: 10/c54ce84cf54b8bda1a37a10dfae2e49e5b6cdf5dd98b399efa8b8a80a286b3f8f27bde53202cb308353bfd98719938991a78bed6e43f81f13b17f8181b7b82eb + "@noble/hashes": "npm:1.4.0" + checksum: 10/d7707d756a887a0daf9eba709526017ac6905d4be58760947e0f0652961926295ba62a5a699d9a9f0bf2a2e0c6803381373e14542be5ff3885b3434bb59be86c languageName: node linkType: hard @@ -4207,20 +4212,13 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": +"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 10/e156e65794c473794c52fa9d06baf1eb20903d0d96719530f523cc4450f6c721a957c544796e6efd0197b2296e7cd70efeb312f861465e17940a3e3c7e0febc6 languageName: node linkType: hard -"@noble/hashes@npm:1.7.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.4.0": - version: 1.7.0 - resolution: "@noble/hashes@npm:1.7.0" - checksum: 10/ab038a816c8c9bb986e92797e3d9c5a5b37c020e0c3edc55bcae5061dbdd457f1f0a22787f83f4787c17415ba0282a20a1e455d36ed0cdcace4ce21ef1869f60 - languageName: node - linkType: hard - "@noble/hashes@npm:~1.3.2": version: 1.3.3 resolution: "@noble/hashes@npm:1.3.3" @@ -4275,19 +4273,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/agent@npm:^3.0.0": - version: 3.0.0 - resolution: "@npmcli/agent@npm:3.0.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^10.0.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10/775c9a7eb1f88c195dfb3bce70c31d0fe2a12b28b754e25c08a3edb4bc4816bfedb7ac64ef1e730579d078ca19dacf11630e99f8f3c3e0fd7b23caa5fd6d30a6 - languageName: node - linkType: hard - "@npmcli/fs@npm:^3.1.0": version: 3.1.1 resolution: "@npmcli/fs@npm:3.1.1" @@ -4297,15 +4282,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/fs@npm:4.0.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/405c4490e1ff11cf299775449a3c254a366a4b1ffc79d87159b0ee7d5558ac9f6a2f8c0735fd6ff3873cef014cb1a44a5f9127cb6a1b2dbc408718cca9365b5a - languageName: node - linkType: hard - "@npmcli/git@npm:^5.0.0": version: 5.0.8 resolution: "@npmcli/git@npm:5.0.8" @@ -4331,8 +4307,8 @@ __metadata: linkType: hard "@npmcli/package-json@npm:^5.0.0": - version: 5.2.1 - resolution: "@npmcli/package-json@npm:5.2.1" + version: 5.2.0 + resolution: "@npmcli/package-json@npm:5.2.0" dependencies: "@npmcli/git": "npm:^5.0.0" glob: "npm:^10.2.2" @@ -4341,7 +4317,7 @@ __metadata: normalize-package-data: "npm:^6.0.0" proc-log: "npm:^4.0.0" semver: "npm:^7.5.3" - checksum: 10/304a819b93f79a6e0e56cb371961a66d2db72142e310d545ecbbbe4d917025a30601aa8e63a5f0cc28f0fe281c116bdaf79b334619b105a1d027a2b769ecd137 + checksum: 10/c3d2218877bfc005bca3b7a11f53825bf16a68811b8e8ed0c9b219cceb8e8e646d70efab8c5d6decbd8007f286076468b3f456dab4d41d648aff73a5f3a6fce2 languageName: node linkType: hard @@ -4480,17 +4456,10 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3": - version: 1.2.1 - resolution: "@scure/base@npm:1.2.1" - checksum: 10/f7bdd17618ccae7a74c8cbe410a235e4adbe54aa8afe4e2fb1294338aa92f6fd04b1f1f5dea60552f638b5f5e3e74902b7baf59d3954e5e42c0a36c6baa2ebe0 - languageName: node - linkType: hard - -"@scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": - version: 1.1.9 - resolution: "@scure/base@npm:1.1.9" - checksum: 10/f0ab7f687bbcdee2a01377fe3cd808bf63977999672751295b6a92625d5322f4754a96d40f6bd579bc367aad48ecf8a4e6d0390e70296e6ded1076f52adb16bb +"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": + version: 1.1.7 + resolution: "@scure/base@npm:1.1.7" + checksum: 10/fc50ffaab36cb46ff9fa4dc5052a06089ab6a6707f63d596bb34aaaec76173c9a564ac312a0b981b5e7a5349d60097b8878673c75d6cbfc4da7012b63a82099b languageName: node linkType: hard @@ -4648,8 +4617,8 @@ __metadata: linkType: hard "@ts-bridge/cli@npm:^0.6.1": - version: 0.6.2 - resolution: "@ts-bridge/cli@npm:0.6.2" + version: 0.6.1 + resolution: "@ts-bridge/cli@npm:0.6.1" dependencies: "@ts-bridge/resolver": "npm:^0.2.0" chalk: "npm:^5.3.0" @@ -4660,7 +4629,7 @@ __metadata: bin: ts-bridge: ./dist/index.js tsbridge: ./dist/index.js - checksum: 10/df690edb0c78eaa91bea93582d628ef3ee0b2555fc27f9fc12ee1eb29d681b387ba76788359190ec330e29d8a31ba8974d2420d2b8dc16adc28c669a18f76de1 + checksum: 10/1cbb8fbfc7f58b804553ab9bc06b689b409d4cdd0f1e960a0ea87971ec7885b5ee2a86cb192d955c7d3611afcadb960e7dfee66aeca60f798a70e7f97aa969c3 languageName: node linkType: hard @@ -4741,11 +4710,11 @@ __metadata: linkType: hard "@types/bn.js@npm:^5.1.0, @types/bn.js@npm:^5.1.5": - version: 5.1.6 - resolution: "@types/bn.js@npm:5.1.6" + version: 5.1.5 + resolution: "@types/bn.js@npm:5.1.5" dependencies: "@types/node": "npm:*" - checksum: 10/db565b5a2af59b09459d74441153bf23a0e80f1fb2d070330786054e7ce1a7285dc40afcd8f289426c61a83166bdd70814f70e2d439744686aac5d3ea75daf13 + checksum: 10/9719330c86aeae0a6a447c974cf0f853ba3660ede20de61f435b03d699e30e6d8b35bf71a8dc9fdc8317784438e83177644ba068ed653d0ae0106e1ecbfe289e languageName: node linkType: hard @@ -4859,12 +4828,12 @@ __metadata: linkType: hard "@types/jest@npm:*": - version: 29.5.14 - resolution: "@types/jest@npm:29.5.14" + version: 29.5.12 + resolution: "@types/jest@npm:29.5.12" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b + checksum: 10/312e8dcf92cdd5a5847d6426f0940829bca6fe6b5a917248f3d7f7ef5d85c9ce78ef05e47d2bbabc40d41a930e0e36db2d443d2610a9e3db9062da2d5c904211 languageName: node linkType: hard @@ -4895,9 +4864,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.191": - version: 4.17.14 - resolution: "@types/lodash@npm:4.17.14" - checksum: 10/6ee40725f3e192f5ef1f493caca19210aa7acd7adc3136b8dba84d418a35be0abea0668105aed9f696ad62a54310a9c0d328971ad4b157f5bcda700424ed5aae + version: 4.17.7 + resolution: "@types/lodash@npm:4.17.7" + checksum: 10/b8177f19cf962414a66989837481b13f546afc2e98e8d465bec59e6ac03a59c584eb7053ce511cde3a09c5f3096d22a5ae22cfb56b23f3b0da75b0743b6b1a44 languageName: node linkType: hard @@ -4916,36 +4885,34 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": - version: 22.10.6 - resolution: "@types/node@npm:22.10.6" + version: 22.5.0 + resolution: "@types/node@npm:22.5.0" dependencies: - undici-types: "npm:~6.20.0" - checksum: 10/ac93c9b6337ddb70176abade1ca4cdec24cde93cfc19023f3e001d80cb42f1d3c2487dd1626ce016985953319de30528d9e73dc5c6e2e28be9eaa9ec0237fc1d + undici-types: "npm:~6.19.2" + checksum: 10/89af3bd217b1559b645a9ed16d4ae3add75749814cbd8eefddd1b96003d1973afb1c8a2b23d69f3a8cc6c532e3aa185eaf5cc29a6e7c42c311a2aad4c99430ae languageName: node linkType: hard -"@types/node@npm:22.7.5": - version: 22.7.5 - resolution: "@types/node@npm:22.7.5" - dependencies: - undici-types: "npm:~6.19.2" - checksum: 10/e8ba102f8c1aa7623787d625389be68d64e54fcbb76d41f6c2c64e8cf4c9f4a2370e7ef5e5f1732f3c57529d3d26afdcb2edc0101c5e413a79081449825c57ac +"@types/node@npm:18.15.13": + version: 18.15.13 + resolution: "@types/node@npm:18.15.13" + checksum: 10/b9bbe923573797ef7c5fd2641a6793489e25d9369c32aeadcaa5c7c175c85b42eb12d6fe173f6781ab6f42eaa1ebd9576a419eeaa2a1ec810094adb8adaa9a54 languageName: node linkType: hard "@types/node@npm:^16.18.54": - version: 16.18.123 - resolution: "@types/node@npm:16.18.123" - checksum: 10/461cb72845a539941e38720362a391e873b5ae26c8eabc04252ed883a165d15281cc7a45da7a47b3c4e7b8cf59da8a2d9025aae9b9b74ecfdc7d3147a638a6c0 + version: 16.18.106 + resolution: "@types/node@npm:16.18.106" + checksum: 10/1970719a048bfc56554f8e132e8e5292c197d6e023d334190b0d3817a05a12bfb6537eaa24778ddb695d2073195f0545e5a4b6bcaf81b656994bbca39f349c3b languageName: node linkType: hard "@types/node@npm:^18.17.15": - version: 18.19.70 - resolution: "@types/node@npm:18.19.70" + version: 18.19.68 + resolution: "@types/node@npm:18.19.68" dependencies: undici-types: "npm:~5.26.4" - checksum: 10/374abb7e75f7f8b2418cde5b0a8dae0032d4e1e3a76097a507a90ed9e66e40c12d19b75493db3aa9d4f92b03ae90d7d9f67c7d64c7f73f20145577350adf0e9b + checksum: 10/024a4a8eeca21c0d1eaa575036dbc44528eae180821de71b77868ddc24d18032b988582046db4f7ea2643970a5169d790e1884153472145de07d629bc2ce2ec6 languageName: node linkType: hard @@ -5099,15 +5066,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.20.0, @typescript-eslint/eslint-plugin@npm:^8.7.0": - version: 8.20.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.20.0" +"@typescript-eslint/eslint-plugin@npm:8.19.1, @typescript-eslint/eslint-plugin@npm:^8.7.0": + version: 8.19.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.19.1" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.20.0" - "@typescript-eslint/type-utils": "npm:8.20.0" - "@typescript-eslint/utils": "npm:8.20.0" - "@typescript-eslint/visitor-keys": "npm:8.20.0" + "@typescript-eslint/scope-manager": "npm:8.19.1" + "@typescript-eslint/type-utils": "npm:8.19.1" + "@typescript-eslint/utils": "npm:8.19.1" + "@typescript-eslint/visitor-keys": "npm:8.19.1" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -5116,64 +5083,64 @@ __metadata: "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/9f027dc0eb7b4b0afed41a6f16a731321fb45b621722ddc68d6c87c708021f10cb84efbb6bacc75c91e60a7619c9957bc9ed557bfb5925900b866ef7d6d6b8a2 + checksum: 10/c9a6d3181ec01068075b85ad3ac454910b4452281d60c775cc7229827f6d6a076b7336f5f07a7ad89bf08b3224f6a49aa20342b9438702393bee0aa7315d23b2 languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.20.0, @typescript-eslint/parser@npm:^8.7.0": - version: 8.20.0 - resolution: "@typescript-eslint/parser@npm:8.20.0" +"@typescript-eslint/parser@npm:8.19.1, @typescript-eslint/parser@npm:^8.7.0": + version: 8.19.1 + resolution: "@typescript-eslint/parser@npm:8.19.1" dependencies: - "@typescript-eslint/scope-manager": "npm:8.20.0" - "@typescript-eslint/types": "npm:8.20.0" - "@typescript-eslint/typescript-estree": "npm:8.20.0" - "@typescript-eslint/visitor-keys": "npm:8.20.0" + "@typescript-eslint/scope-manager": "npm:8.19.1" + "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/typescript-estree": "npm:8.19.1" + "@typescript-eslint/visitor-keys": "npm:8.19.1" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/52960498961d0927e9dc60f724e9df6445357db06133a7c00cc840823d92c8dd9f0b47cebc026aef12c316748732e5c04ca61861db05d2264cf53ab88fdb34e9 + checksum: 10/da3db63ff655cf0fb91745ba8e52d853386f601cf6106d36f4541efcb9e2c6c3b82c6743b15680eff9eafeccaf31c9b26191a955e66ae19de9172f67335463ab languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.20.0, @typescript-eslint/scope-manager@npm:^8.1.0": - version: 8.20.0 - resolution: "@typescript-eslint/scope-manager@npm:8.20.0" +"@typescript-eslint/scope-manager@npm:8.19.1, @typescript-eslint/scope-manager@npm:^8.1.0": + version: 8.19.1 + resolution: "@typescript-eslint/scope-manager@npm:8.19.1" dependencies: - "@typescript-eslint/types": "npm:8.20.0" - "@typescript-eslint/visitor-keys": "npm:8.20.0" - checksum: 10/0ea30ba12007d77659b43bbbec463c142d3d4d36f7de381d1f59a97f95240203e79dd9a24040be7113eb4c8bd231339f9322d9a40e1a1fb178e9ac52d9c559ab + "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/visitor-keys": "npm:8.19.1" + checksum: 10/6ffc78b15367f211eb6650459ca2bb6bfe4c1fa95a3474adc08ee9a20c250b2e0e02fd99be36bd3dad74967ecd9349e792b5d818d85735cba40f1b5c236074d1 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.20.0": - version: 8.20.0 - resolution: "@typescript-eslint/type-utils@npm:8.20.0" +"@typescript-eslint/type-utils@npm:8.19.1": + version: 8.19.1 + resolution: "@typescript-eslint/type-utils@npm:8.19.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.20.0" - "@typescript-eslint/utils": "npm:8.20.0" + "@typescript-eslint/typescript-estree": "npm:8.19.1" + "@typescript-eslint/utils": "npm:8.19.1" debug: "npm:^4.3.4" ts-api-utils: "npm:^2.0.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/cdde9d30e684c0c44434ed97e11c962d8f80f53b8a0050e8fe10b7f20c26f7684a340acd21c83bdcbc1feb3eef334eb5b0fef31d2d330648e52d4afe57942a95 + checksum: 10/123ecda88b057d6a4b68226701f435661440a420fda88cba60b49d7fb3e4f49483164ff174f259e28c0beabb0ed04500462a20faefd78331ba202bf54b01e3ef languageName: node linkType: hard -"@typescript-eslint/types@npm:8.20.0": - version: 8.20.0 - resolution: "@typescript-eslint/types@npm:8.20.0" - checksum: 10/434859226136ea9e439e8abf5dcf813ea3b55b7e4af6ecc8d290a2f925e3baad0579765ac32d21005b0caedaac38b8624131f87b572c84ca92ac3e742a52e149 +"@typescript-eslint/types@npm:8.19.1": + version: 8.19.1 + resolution: "@typescript-eslint/types@npm:8.19.1" + checksum: 10/5833a5f8fdac4a490dd3906a0243a0713fbf138fabb451870c70b0b089c539a9624b467b0913ddc0a225a8284342e7fd31cd506dec53c1a6d8f3c8c8902b9cae languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.20.0": - version: 8.20.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.20.0" +"@typescript-eslint/typescript-estree@npm:8.19.1": + version: 8.19.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.19.1" dependencies: - "@typescript-eslint/types": "npm:8.20.0" - "@typescript-eslint/visitor-keys": "npm:8.20.0" + "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/visitor-keys": "npm:8.19.1" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" @@ -5182,32 +5149,32 @@ __metadata: ts-api-utils: "npm:^2.0.0" peerDependencies: typescript: ">=4.8.4 <5.8.0" - checksum: 10/8dbb1b835492574b4c8765c64964179e258f811d3f4cd7f6a90e1cb297520090728f77366cfb05233c26f4c07b1f2be990fa3f54eae9e7abc218005d51ee6804 + checksum: 10/5de467452d5ef1a380d441b06cd0134652a0c98cdb4ce31b93eb589f7dc75ef60364d03fd80ca0a48d0c8b268f7258d4f6528b16fe1b89442d60a4bc960fe5f5 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.20.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": - version: 8.20.0 - resolution: "@typescript-eslint/utils@npm:8.20.0" +"@typescript-eslint/utils@npm:8.19.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": + version: 8.19.1 + resolution: "@typescript-eslint/utils@npm:8.19.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.20.0" - "@typescript-eslint/types": "npm:8.20.0" - "@typescript-eslint/typescript-estree": "npm:8.20.0" + "@typescript-eslint/scope-manager": "npm:8.19.1" + "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/typescript-estree": "npm:8.19.1" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/d4369f3e535d5c75eedce2b8f4ea1e857b75ac2ea73f2c707ba3fa3533053f63d8c22f085e58573a2d035d61ed69f6fef4ba0bc7c7df173d26b3adce73bf6aed + checksum: 10/bb92116a53fe143ee87e830941afb21d4222a64ca3f2b6dac5c2d9984f981408e60e52b04c32d95208896075ac222fb4ee631c5b0c4826b87d4bd8091c421ab1 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.20.0": - version: 8.20.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.20.0" +"@typescript-eslint/visitor-keys@npm:8.19.1": + version: 8.19.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.19.1" dependencies: - "@typescript-eslint/types": "npm:8.20.0" + "@typescript-eslint/types": "npm:8.19.1" eslint-visitor-keys: "npm:^4.2.0" - checksum: 10/31f32efb975a10cb1b0028a6d0f47b65acb322ed446f93862e39a3a0d5b55a2354ab0f062794fb148f45c8ce09fb93878d8a101a72d09d4a06ffa2f0d163d65f + checksum: 10/510eb196e7b7d59d3981d672a75454615159e931fe78e2a64b09607c3cfa45110709b0eb5ac3dd271d757a0d98cf4868ad2f45bf9193f96e9efec3efa92a19c1 languageName: node linkType: hard @@ -5218,60 +5185,60 @@ __metadata: languageName: node linkType: hard -"@vue/compiler-core@npm:3.5.13": - version: 3.5.13 - resolution: "@vue/compiler-core@npm:3.5.13" +"@vue/compiler-core@npm:3.4.38": + version: 3.4.38 + resolution: "@vue/compiler-core@npm:3.4.38" dependencies: - "@babel/parser": "npm:^7.25.3" - "@vue/shared": "npm:3.5.13" + "@babel/parser": "npm:^7.24.7" + "@vue/shared": "npm:3.4.38" entities: "npm:^4.5.0" estree-walker: "npm:^2.0.2" source-map-js: "npm:^1.2.0" - checksum: 10/22f042bb47c8a1edb9d602e24da8092ab542d5640f0459a9b99ecf35f90e96678f870209dd30f774f5340c6d817d3c5a46ca49cefb9659ee5b228bd42d1f076a + checksum: 10/16449e9083c290e6c13e1cc0cb0a0a457817a52533d10902388c872fb1337ba0fa29fb7b8394df5a10f5ed3bad264d6c386f9eaf47c07982a543f277dbee9b8a languageName: node linkType: hard -"@vue/compiler-dom@npm:3.5.13": - version: 3.5.13 - resolution: "@vue/compiler-dom@npm:3.5.13" +"@vue/compiler-dom@npm:3.4.38": + version: 3.4.38 + resolution: "@vue/compiler-dom@npm:3.4.38" dependencies: - "@vue/compiler-core": "npm:3.5.13" - "@vue/shared": "npm:3.5.13" - checksum: 10/5dc628c52091264a443c2d7326b759d7d3999c7e9c00078c2eb370b778e60b9f2ef258a8decf2fd97c8fa0923f895d449eabc1e5bc3d8a45d3ef99c9eb0599d7 + "@vue/compiler-core": "npm:3.4.38" + "@vue/shared": "npm:3.4.38" + checksum: 10/4012fab212dc0628ef72f5ae13aa2dd551efb8be7f2aa8abe2a1db15058ddda29912a1e3aa1fc6712e2d8efe84724f16a907ad2cda987631bfc79330afc8d451 languageName: node linkType: hard "@vue/compiler-sfc@npm:^3.3.4": - version: 3.5.13 - resolution: "@vue/compiler-sfc@npm:3.5.13" - dependencies: - "@babel/parser": "npm:^7.25.3" - "@vue/compiler-core": "npm:3.5.13" - "@vue/compiler-dom": "npm:3.5.13" - "@vue/compiler-ssr": "npm:3.5.13" - "@vue/shared": "npm:3.5.13" + version: 3.4.38 + resolution: "@vue/compiler-sfc@npm:3.4.38" + dependencies: + "@babel/parser": "npm:^7.24.7" + "@vue/compiler-core": "npm:3.4.38" + "@vue/compiler-dom": "npm:3.4.38" + "@vue/compiler-ssr": "npm:3.4.38" + "@vue/shared": "npm:3.4.38" estree-walker: "npm:^2.0.2" - magic-string: "npm:^0.30.11" - postcss: "npm:^8.4.48" + magic-string: "npm:^0.30.10" + postcss: "npm:^8.4.40" source-map-js: "npm:^1.2.0" - checksum: 10/08d55bbdbe86ad0a1fc0501dbf5f535161d35ecb378adb478dd4a75b97e8d21852516966c0ad8aed1d6da11b0d8280b7848ff142b4181cb8f24eaaecd7827f73 + checksum: 10/3eec1ddc03e06a162087dbbff9679f941ff34c43e553006aa2717c6a396445f488b62b89afa9cf65688468a05d8517bf1ee64936ad78d7ba6647a850a089e0e0 languageName: node linkType: hard -"@vue/compiler-ssr@npm:3.5.13": - version: 3.5.13 - resolution: "@vue/compiler-ssr@npm:3.5.13" +"@vue/compiler-ssr@npm:3.4.38": + version: 3.4.38 + resolution: "@vue/compiler-ssr@npm:3.4.38" dependencies: - "@vue/compiler-dom": "npm:3.5.13" - "@vue/shared": "npm:3.5.13" - checksum: 10/09f2706455a7d8a5acc67c98120d28d0105d006184402b045636be7791939f5a77fd1c37657047b0129fa431f03437dcab9befc6baa172367ecdef7618407149 + "@vue/compiler-dom": "npm:3.4.38" + "@vue/shared": "npm:3.4.38" + checksum: 10/3ee052c8f10bf18db5d6788df21105698c139fac1de6c82532878cca86be4d052510a216184b3ea73331d84befcefd3f9ada11470c862f03696fed96ce1005cb languageName: node linkType: hard -"@vue/shared@npm:3.5.13": - version: 3.5.13 - resolution: "@vue/shared@npm:3.5.13" - checksum: 10/5c0c24f443533392dde08c3e4272ff2e19af9762f90baeaa808850e05106537bbd9e2d2ad2081d979b8c4bc89902395b46036b67f74c60b76025924de37833b1 +"@vue/shared@npm:3.4.38": + version: 3.4.38 + resolution: "@vue/shared@npm:3.4.38" + checksum: 10/46bfc1f3932fd154ff84dcd267cae4db730c98db433c848d40c9c0dc23dcabdb5efe96a3a378c9ed3b7e8281ca17e2753f0ce98ae43b54b315550dfaccb56868 languageName: node linkType: hard @@ -5283,17 +5250,17 @@ __metadata: linkType: hard "@yarnpkg/cli@npm:^4.5.3": - version: 4.6.0 - resolution: "@yarnpkg/cli@npm:4.6.0" + version: 4.5.3 + resolution: "@yarnpkg/cli@npm:4.5.3" dependencies: - "@yarnpkg/core": "npm:^4.2.0" + "@yarnpkg/core": "npm:^4.1.6" "@yarnpkg/fslib": "npm:^3.1.1" "@yarnpkg/libzip": "npm:^3.1.0" "@yarnpkg/parsers": "npm:^3.0.2" "@yarnpkg/plugin-compat": "npm:^4.0.10" "@yarnpkg/plugin-constraints": "npm:^4.0.2" "@yarnpkg/plugin-dlx": "npm:^4.0.0" - "@yarnpkg/plugin-essentials": "npm:^4.3.0" + "@yarnpkg/plugin-essentials": "npm:^4.2.2" "@yarnpkg/plugin-exec": "npm:^3.0.0" "@yarnpkg/plugin-file": "npm:^3.0.0" "@yarnpkg/plugin-git": "npm:^3.1.0" @@ -5307,12 +5274,12 @@ __metadata: "@yarnpkg/plugin-npm-cli": "npm:^4.0.4" "@yarnpkg/plugin-pack": "npm:^4.0.0" "@yarnpkg/plugin-patch": "npm:^4.0.1" - "@yarnpkg/plugin-pnp": "npm:^4.0.6" + "@yarnpkg/plugin-pnp": "npm:^4.0.5" "@yarnpkg/plugin-pnpm": "npm:^2.0.0" "@yarnpkg/plugin-stage": "npm:^4.0.0" "@yarnpkg/plugin-typescript": "npm:^4.1.1" "@yarnpkg/plugin-version": "npm:^4.0.4" - "@yarnpkg/plugin-workspace-tools": "npm:^4.1.2" + "@yarnpkg/plugin-workspace-tools": "npm:^4.1.1" "@yarnpkg/shell": "npm:^4.1.1" ci-info: "npm:^4.0.0" clipanion: "npm:^4.0.0-rc.2" @@ -5320,14 +5287,14 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/core": ^4.2.0 - checksum: 10/8bfe4ea7165b0928bbc5542e520d7e638d66cbb21797269bb4eb1e7d136e2dad14495e9698ce89ffe5d5129debcd5bcc337bf0e5b1849f393c8127b2ad484708 + "@yarnpkg/core": ^4.1.6 + checksum: 10/bd3f8748cc4f3b041f815b0fa5287c8c181a8d3a600a9b30694180bee6cf37fcede2296d46ff20d3ab04e837be33401824432c57712aa8367690c741b809826e languageName: node linkType: hard -"@yarnpkg/core@npm:^4.1.6, @yarnpkg/core@npm:^4.2.0": - version: 4.2.0 - resolution: "@yarnpkg/core@npm:4.2.0" +"@yarnpkg/core@npm:^4.1.6": + version: 4.1.6 + resolution: "@yarnpkg/core@npm:4.1.6" dependencies: "@arcanis/slice-ansi": "npm:^1.1.1" "@types/semver": "npm:^7.1.0" @@ -5355,7 +5322,7 @@ __metadata: treeify: "npm:^1.1.0" tslib: "npm:^2.4.0" tunnel: "npm:^0.0.6" - checksum: 10/fd7f2093dd6a77759c116e79bde2ecd2142bfaa25aa6957c50e8fb42c105f299cf4f779acf4717cd5f95002aa335bbe36e8acd3fbfb573f455f76b5e0c9ec515 + checksum: 10/6a766f3b91485ce210c898468ab51d97fcd49a3b19afd524c1adee031f46322311e559312f245c8ad32c853f6ace3b80665c08612876957dbce49f18fddbbba1 languageName: node linkType: hard @@ -5465,11 +5432,11 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-essentials@npm:^4.3.0": - version: 4.3.0 - resolution: "@yarnpkg/plugin-essentials@npm:4.3.0" +"@yarnpkg/plugin-essentials@npm:^4.2.2": + version: 4.2.2 + resolution: "@yarnpkg/plugin-essentials@npm:4.2.2" dependencies: - "@yarnpkg/fslib": "npm:^3.1.1" + "@yarnpkg/fslib": "npm:^3.1.0" "@yarnpkg/parsers": "npm:^3.0.2" ci-info: "npm:^4.0.0" clipanion: "npm:^4.0.0-rc.2" @@ -5480,10 +5447,10 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/cli": ^4.6.0 - "@yarnpkg/core": ^4.2.0 + "@yarnpkg/cli": ^4.4.0 + "@yarnpkg/core": ^4.1.2 "@yarnpkg/plugin-git": ^3.1.0 - checksum: 10/52a5672dc47589d5b850b3c849e063b414289bf457bced7066eba8dc7962bfa024f17c775c0f432a5d1511e07b61a64244525fcb7647817138ad6fde25855f4d + checksum: 10/976a5c57fb5ba8446bdd9aad6b0b9b3a6e20699027c03df0190ce73e2fb4c77599ca16d8bc4ddf861c866abc853458e0e9cbd920e0b52e60953dd095cfa0394d languageName: node linkType: hard @@ -5688,20 +5655,20 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-pnp@npm:^4.0.0, @yarnpkg/plugin-pnp@npm:^4.0.5, @yarnpkg/plugin-pnp@npm:^4.0.6": - version: 4.0.6 - resolution: "@yarnpkg/plugin-pnp@npm:4.0.6" +"@yarnpkg/plugin-pnp@npm:^4.0.0, @yarnpkg/plugin-pnp@npm:^4.0.5": + version: 4.0.5 + resolution: "@yarnpkg/plugin-pnp@npm:4.0.5" dependencies: - "@yarnpkg/fslib": "npm:^3.1.1" + "@yarnpkg/fslib": "npm:^3.1.0" "@yarnpkg/plugin-stage": "npm:^4.0.0" - "@yarnpkg/pnp": "npm:^4.0.8" + "@yarnpkg/pnp": "npm:^4.0.5" clipanion: "npm:^4.0.0-rc.2" micromatch: "npm:^4.0.2" tslib: "npm:^2.4.0" peerDependencies: - "@yarnpkg/cli": ^4.6.0 - "@yarnpkg/core": ^4.2.0 - checksum: 10/263b92aa005c929d31470484139cc28b42e86386da47e2a0303c8a45b2bdf7d1a2c72d881b9bd59659c725d6609523ad784ee175b4e8f987531802ebaf96f580 + "@yarnpkg/cli": ^4.2.2 + "@yarnpkg/core": ^4.0.5 + checksum: 10/7d3277ffbb71ba8f6a1a647f4f66ff618c8645556784f3acf9fa198bbb2fad650043a8a927b7bc446f4748b1433a03219ea7030414b07417b3c31b8390631c0a languageName: node linkType: hard @@ -5774,9 +5741,9 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/plugin-workspace-tools@npm:^4.1.2": - version: 4.1.2 - resolution: "@yarnpkg/plugin-workspace-tools@npm:4.1.2" +"@yarnpkg/plugin-workspace-tools@npm:^4.1.1": + version: 4.1.1 + resolution: "@yarnpkg/plugin-workspace-tools@npm:4.1.1" dependencies: "@yarnpkg/fslib": "npm:^3.1.1" clipanion: "npm:^4.0.0-rc.2" @@ -5785,20 +5752,20 @@ __metadata: tslib: "npm:^2.4.0" typanion: "npm:^3.14.0" peerDependencies: - "@yarnpkg/cli": ^4.6.0 - "@yarnpkg/core": ^4.2.0 + "@yarnpkg/cli": ^4.5.3 + "@yarnpkg/core": ^4.1.6 "@yarnpkg/plugin-git": ^3.1.0 - checksum: 10/f6f99728ad796c6bf0ce56d8a69dc2a93094ae787d03b67c8a32e981a4ad8803a2e906616089aa21ee686505aedf0f0b8d986bb2f40842470d8529ee9331ac7b + checksum: 10/0011a6e3973b5b15029e074d4aa9caae7bd44d3a989b9cff3d9e6ae1d1a58cfd7c308dfbe0acef18e65c966233794a17275f996e5f5fbdc4f6115b2c1cb194fa languageName: node linkType: hard -"@yarnpkg/pnp@npm:^4.0.6, @yarnpkg/pnp@npm:^4.0.7, @yarnpkg/pnp@npm:^4.0.8": - version: 4.0.8 - resolution: "@yarnpkg/pnp@npm:4.0.8" +"@yarnpkg/pnp@npm:^4.0.5, @yarnpkg/pnp@npm:^4.0.6, @yarnpkg/pnp@npm:^4.0.7": + version: 4.0.7 + resolution: "@yarnpkg/pnp@npm:4.0.7" dependencies: "@types/node": "npm:^18.17.15" "@yarnpkg/fslib": "npm:^3.1.1" - checksum: 10/1dcef20bdd92e539df84ebe58c513d2fe486bda490666ad6883a5f4bf2c2fd9f057aa906691f8e9271331e2734e73b0d299e4dc108a75f43a707efbbb3b918ae + checksum: 10/0a13983923b7cb5d3e6f70cb87deed07f3e71a57bcc46c51bf244bdad6c524002999bb02f2b4a0737d1747e72c7353b97b5ecc3626dda3580b97bfbb41506f32 languageName: node linkType: hard @@ -5939,10 +5906,12 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.3 - resolution: "agent-base@npm:7.1.3" - checksum: 10/3db6d8d4651f2aa1a9e4af35b96ab11a7607af57a24f3bc721a387eaa3b5f674e901f0a648b0caefd48f3fd117c7761b79a3b55854e2aebaa96c3f32cf76af84 +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: "npm:^4.3.4" + checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 languageName: node linkType: hard @@ -6015,9 +5984,9 @@ __metadata: linkType: hard "ansi-regex@npm:^6.0.1": - version: 6.1.0 - resolution: "ansi-regex@npm:6.1.0" - checksum: 10/495834a53b0856c02acd40446f7130cb0f8284f4a39afdab20d5dc42b2e198b1196119fe887beed8f9055c4ff2055e3b2f6d4641d0be018cdfb64fedf6fc1aac + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 languageName: node linkType: hard @@ -6139,6 +6108,15 @@ __metadata: languageName: node linkType: hard +"async-mutex@npm:^0.3.1": + version: 0.3.2 + resolution: "async-mutex@npm:0.3.2" + dependencies: + tslib: "npm:^2.3.1" + checksum: 10/cf0b02f7f916d202a727e15a64d51110c3258a719588ca263875024172aa9368efa5dbec6dc4f4fd10e35744e238e1075306a93ce86549de642d5f7d0c06bc23 + languageName: node + linkType: hard + "async-mutex@npm:^0.5.0": version: 0.5.0 resolution: "async-mutex@npm:0.5.0" @@ -6172,20 +6150,20 @@ __metadata: linkType: hard "axios@npm:^1.7.4": - version: 1.7.9 - resolution: "axios@npm:1.7.9" + version: 1.7.5 + resolution: "axios@npm:1.7.5" dependencies: follow-redirects: "npm:^1.15.6" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: 10/b7a5f660ea53ba9c2a745bf5ad77ad8bf4f1338e13ccc3f9f09f810267d6c638c03dac88b55dae8dc98b79c57d2d6835be651d58d2af97c174f43d289a9fd007 + checksum: 10/6cbcfe943a84089f420a900a3a3aeb54ee94dcc9c2b81b150434896357be5d1079eff0b1bbb628597371e79f896b1bc5776df04184756ba99656ff31df9a75bf languageName: node linkType: hard "b4a@npm:^1.6.4": - version: 1.6.7 - resolution: "b4a@npm:1.6.7" - checksum: 10/1ac056e3bce378d4d3e570e57319360a9d3125ab6916a1921b95bea33d9ee646698ebc75467561fd6fcc80ff697612124c89bb9b95e80db94c6dc23fcb977705 + version: 1.6.6 + resolution: "b4a@npm:1.6.6" + checksum: 10/6154a36bd78b53ecd2843a829352532a1bf9fc8081dab339ba06ca3c9ffcf25d340c3b18fe4ba0fc17a546a54c1ed814cea92cd6b895f6bd2837ca4ee0fc9f52 languageName: node linkType: hard @@ -6328,9 +6306,9 @@ __metadata: linkType: hard "bare-events@npm:^2.2.0": - version: 2.5.4 - resolution: "bare-events@npm:2.5.4" - checksum: 10/135ef380b13f554ca2c6905bdbcfac8edae08fce85b7f953fa01f09a9f5b0da6a25e414111659bc9a6118216f0dd1f732016acd11ce91517f2afb26ebeb4b721 + version: 2.4.2 + resolution: "bare-events@npm:2.4.2" + checksum: 10/c1006ad13b7e62a412466d4eac8466b4ceb46ce84a5e2fc164cd4b10edaaa5016adc684147134b67a6a3865aaf5aa007191647bdb5dbf859b1d5735d2a9ddf3b languageName: node linkType: hard @@ -6434,9 +6412,9 @@ __metadata: linkType: hard "bn.js@npm:^4.11.9": - version: 4.12.1 - resolution: "bn.js@npm:4.12.1" - checksum: 10/07f22df8880b423c4890648e95791319898b96712b6ebc5d6b1082b34074f09dedb8601e717d67f905ce29bb1a5313f9a2b1a2015a679e42c9eed94392c0d379 + version: 4.12.0 + resolution: "bn.js@npm:4.12.0" + checksum: 10/10f8db196d3da5adfc3207d35d0a42aa29033eb33685f20ba2c36cadfe2de63dad05df0a20ab5aae01b418d1c4b3d4d205273085262fa020d17e93ff32b67527 languageName: node linkType: hard @@ -6611,26 +6589,6 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^19.0.1": - version: 19.0.1 - resolution: "cacache@npm:19.0.1" - dependencies: - "@npmcli/fs": "npm:^4.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^10.0.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^12.0.0" - tar: "npm:^7.4.3" - unique-filename: "npm:^4.0.0" - checksum: 10/ea026b27b13656330c2bbaa462a88181dcaa0435c1c2e705db89b31d9bdf7126049d6d0445ba746dca21454a0cfdf1d6f47fd39d34c8c8435296b30bc5738a13 - languageName: node - linkType: hard - "cacheable-lookup@npm:^5.0.3": version: 5.0.4 resolution: "cacheable-lookup@npm:5.0.4" @@ -6653,35 +6611,16 @@ __metadata: languageName: node linkType: hard -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1": - version: 1.0.1 - resolution: "call-bind-apply-helpers@npm:1.0.1" +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.7": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" dependencies: + es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" function-bind: "npm:^1.1.2" - checksum: 10/6e30c621170e45f1fd6735e84d02ee8e02a3ab95cb109499d5308cbe5d1e84d0cd0e10b48cc43c76aa61450ae1b03a7f89c37c10fc0de8d4998b42aab0f268cc - languageName: node - linkType: hard - -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" - dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.2" - checksum: 10/659b03c79bbfccf0cde3a79e7d52570724d7290209823e1ca5088f94b52192dc1836b82a324d0144612f816abb2f1734447438e38d9dafe0b3f82c2a1b9e3bce - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3": - version: 1.0.3 - resolution: "call-bound@npm:1.0.3" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - get-intrinsic: "npm:^1.2.6" - checksum: 10/c39a8245f68cdb7c1f5eea7b3b1e3a7a90084ea6efebb78ebc454d698ade2c2bb42ec033abc35f1e596d62496b6100e9f4cdfad1956476c510130e2cda03266d + set-function-length: "npm:^1.2.1" + checksum: 10/cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 languageName: node linkType: hard @@ -6714,9 +6653,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001692 - resolution: "caniuse-lite@npm:1.0.30001692" - checksum: 10/92449ec9e9ac6cd8ce7ecc18a8759ae34e4b3ef412acd998714ee9d70dc286bc8d0d6e4917fa454798da9b37667eb5b3b41386bc9d25e4274d0b9c7af8339b0e + version: 1.0.30001690 + resolution: "caniuse-lite@npm:1.0.30001690" + checksum: 10/9fb4659eb09a298601b9593739072c481e2f5cc524bd0530e5e0f002e66246da5e866669854dfc0d53195ee36b201dab02f7933a7cdf60ccba7adb2d4a304caf languageName: node linkType: hard @@ -6748,9 +6687,9 @@ __metadata: linkType: hard "chalk@npm:^5.3.0": - version: 5.4.1 - resolution: "chalk@npm:5.4.1" - checksum: 10/29df3ffcdf25656fed6e95962e2ef86d14dfe03cd50e7074b06bad9ffbbf6089adbb40f75c00744d843685c8d008adaf3aed31476780312553caf07fa86e5bc7 + version: 5.3.0 + resolution: "chalk@npm:5.3.0" + checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea languageName: node linkType: hard @@ -6768,13 +6707,6 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^3.0.0": - version: 3.0.0 - resolution: "chownr@npm:3.0.0" - checksum: 10/b63cb1f73d171d140a2ed8154ee6566c8ab775d3196b0e03a2a94b5f6a0ce7777ee5685ca56849403c8d17bd457a6540672f9a60696a6137c7a409097495b82c - languageName: node - linkType: hard - "ci-info@npm:^2.0.0": version: 2.0.0 resolution: "ci-info@npm:2.0.0" @@ -6797,19 +6729,19 @@ __metadata: linkType: hard "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.6 - resolution: "cipher-base@npm:1.0.6" + version: 1.0.4 + resolution: "cipher-base@npm:1.0.4" dependencies: - inherits: "npm:^2.0.4" - safe-buffer: "npm:^5.2.1" - checksum: 10/faf232deff2351448ea23d265eb8723e035ebbb454baca45fb60c1bd71056ede8b153bef1b221e067f13e6b9288ebb83bb6ae2d5dd4cec285411f9fc22ec1f5b + inherits: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + checksum: 10/3d5d6652ca499c3f7c5d7fdc2932a357ec1e5aa84f2ad766d850efd42e89753c97b795c3a104a8e7ae35b4e293f5363926913de3bf8181af37067d9d541ca0db languageName: node linkType: hard "cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.3.1": - version: 1.4.1 - resolution: "cjs-module-lexer@npm:1.4.1" - checksum: 10/6e830a1e00a34d416949bbc1924f3e8da65cef4a6a09e2b7fa35722e2d1c34bf378d3baca987b698d1cbc3eb83e44b044039b4e82755c96f30e0f03d1d227637 + version: 1.4.0 + resolution: "cjs-module-lexer@npm:1.4.0" + checksum: 10/b041096749792526120d8b8756929f8ef5dd4596502a0e1013f857e3027acd6091915fea77037921d70ee1a99988a100d994d3d3c2e323b04dd4c5ffd516cf13 languageName: node linkType: hard @@ -7012,30 +6944,30 @@ __metadata: linkType: hard "contentful-resolve-response@npm:^1.9.0": - version: 1.9.2 - resolution: "contentful-resolve-response@npm:1.9.2" + version: 1.9.0 + resolution: "contentful-resolve-response@npm:1.9.0" dependencies: fast-copy: "npm:^2.1.7" - checksum: 10/7fce57e33d5f874c65683567af30d1f1c32a8769558479f61b4d465201f8ea979a52b9b31f33d01a5437477aa0195a00565792efba345f2b21689e13519d70b3 + checksum: 10/0c5daa59a3a6b020f9b5316812e3f14e62833b4aead008527c5bfde6549365e8e8e9f373af8836f06ca7b2023d861fdd2c241d3e74d3797133d18983be8bb3b3 languageName: node linkType: hard "contentful-sdk-core@npm:^8.3.1": - version: 8.3.2 - resolution: "contentful-sdk-core@npm:8.3.2" + version: 8.3.1 + resolution: "contentful-sdk-core@npm:8.3.1" dependencies: fast-copy: "npm:^2.1.7" lodash.isplainobject: "npm:^4.0.6" lodash.isstring: "npm:^4.0.1" p-throttle: "npm:^4.1.1" qs: "npm:^6.11.2" - checksum: 10/4af0aba2bb7e3db3ebf260fea74843de89f150f5af883134c370eb695fd8b2587cf94d4524d03020286f565eb3bff7b12d42f2a38718b62eb75cb28556e40f42 + checksum: 10/645d3a5d296d0e2a5ce87cceb04cf1ddf572183b5946cb1b3b717436bc7be96864216225fb845e61850d580436021c6284e7c95da0600a16c89c0af81a5f0d2c languageName: node linkType: hard "contentful@npm:^10.15.0": - version: 10.15.1 - resolution: "contentful@npm:10.15.1" + version: 10.15.0 + resolution: "contentful@npm:10.15.0" dependencies: "@contentful/content-source-maps": "npm:^0.11.0" "@contentful/rich-text-types": "npm:^16.0.2" @@ -7044,7 +6976,7 @@ __metadata: contentful-sdk-core: "npm:^8.3.1" json-stringify-safe: "npm:^5.0.1" type-fest: "npm:^4.0.0" - checksum: 10/eb913a79e38d87bc7fb3a79952e4d7c5a1de5cccfbe0a012e8131c9c1e5a0a525cfcb7eaea971b02fb9e57b9e49c71ce96dd7096c3f65483992017ef70de80e5 + checksum: 10/b57c51faa99074a2f60c930c4827d1f8fe9867a359e53738532bbe859f5d72e750645fa4e195e65ad015811f344d95a0b3cebe6debef7d4e92ce9510bd55939e languageName: node linkType: hard @@ -7406,6 +7338,15 @@ __metadata: languageName: node linkType: hard +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: "npm:^4.0.0" + checksum: 10/fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + languageName: node + linkType: hard + "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -7431,17 +7372,6 @@ __metadata: languageName: node linkType: hard -"dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10/5add88a3d68d42d6e6130a0cac450b7c2edbe73364bbd2fc334564418569bea97c6943a8fcd70e27130bf32afc236f30982fc4905039b703f23e9e0433c29934 - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -7450,9 +7380,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.5.73": - version: 1.5.82 - resolution: "electron-to-chromium@npm:1.5.82" - checksum: 10/2c8e01d71515773d6789013162505a31b831c4f4e7b4a1e9fc65ed6d7e31e21f71b0880dd141eadbb93d89e2a2fce9636ac72604c28fa0960d44e8dacbed431e + version: 1.5.79 + resolution: "electron-to-chromium@npm:1.5.79" + checksum: 10/c5b25ba04b4f4b46c4024b96e00e43adcd6c321b48c74c8d2660f69704901da5a6592009cbf96c36c89e3f6b53d7742e2b89514477fddbccf4e5c4caebed9d49 languageName: node linkType: hard @@ -7560,10 +7490,12 @@ __metadata: languageName: node linkType: hard -"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10/f8dc9e660d90919f11084db0a893128f3592b781ce967e4fccfb8f3106cb83e400a4032c559184ec52ee1dbd4b01e7776c7cd0b3327b1961b1a4a7008920fe78 +"es-define-property@npm:^1.0.0": + version: 1.0.0 + resolution: "es-define-property@npm:1.0.0" + dependencies: + get-intrinsic: "npm:^1.2.4" + checksum: 10/f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 languageName: node linkType: hard @@ -7581,15 +7513,6 @@ __metadata: languageName: node linkType: hard -"es-object-atoms@npm:^1.0.0": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10/54fe77de288451dae51c37bfbfe3ec86732dc3778f98f3eb3bdb4bf48063b2c0b8f9c93542656986149d08aa5be3204286e2276053d19582b76753f1a2728867 - languageName: node - linkType: hard - "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -7731,8 +7654,8 @@ __metadata: linkType: hard "eslint-plugin-jest@npm:^28.8.3": - version: 28.11.0 - resolution: "eslint-plugin-jest@npm:28.11.0" + version: 28.10.0 + resolution: "eslint-plugin-jest@npm:28.10.0" dependencies: "@typescript-eslint/utils": "npm:^6.0.0 || ^7.0.0 || ^8.0.0" peerDependencies: @@ -7744,7 +7667,7 @@ __metadata: optional: true jest: optional: true - checksum: 10/7f3896ec2dc03110688bb9f359a7aa1ba1a6d9a60ffbc3642361c4aaf55afcba9ce36b6609b20b1507028c2170ffe29b0f3e9cc9b7fe12fdd233740a2f9ce0a1 + checksum: 10/cb19f2171e93873d9207425c4fa52ec49018579d73ece23a1ffea90f3ffd284b0e48f74ff4f50b15ff31882b06b03fec0e48c9c6ca830acdeff8931802ef0a9e languageName: node linkType: hard @@ -7788,8 +7711,8 @@ __metadata: linkType: hard "eslint-plugin-prettier@npm:^5.2.1": - version: 5.2.2 - resolution: "eslint-plugin-prettier@npm:5.2.2" + version: 5.2.1 + resolution: "eslint-plugin-prettier@npm:5.2.1" dependencies: prettier-linter-helpers: "npm:^1.0.0" synckit: "npm:^0.9.1" @@ -7803,7 +7726,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 10/292569865fde6a91646037f58105c18225f5cd57e255966f8388b13c196ce023f84e22100408dcd30472c02d0846a897b8afe460ece57dfc23e80e6cac70a644 + checksum: 10/10ddf68215237e327af09a47adab4c63f3885fda4fb28c4c42d1fc5f47d8a0cc45df6484799360ff1417a0aa3c77c3aaac49d7e9dfd145557b17e2d7ecc2a27c languageName: node linkType: hard @@ -7843,16 +7766,16 @@ __metadata: linkType: hard "eslint@npm:^9.11.0": - version: 9.18.0 - resolution: "eslint@npm:9.18.0" + version: 9.17.0 + resolution: "eslint@npm:9.17.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" "@eslint/config-array": "npm:^0.19.0" - "@eslint/core": "npm:^0.10.0" + "@eslint/core": "npm:^0.9.0" "@eslint/eslintrc": "npm:^3.2.0" - "@eslint/js": "npm:9.18.0" - "@eslint/plugin-kit": "npm:^0.2.5" + "@eslint/js": "npm:9.17.0" + "@eslint/plugin-kit": "npm:^0.2.3" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.1" @@ -7887,7 +7810,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/85f22991aab4b0809fdfc557ec2bd309062e7211b631674e71827a73c45e44febaa80dedda35150154e331a2d372c3a25e8e5dd4a99dc8a982fe8f7d645d859f + checksum: 10/a48ee67dd4e737974bbb49ca5d12d0ce35bcd874507807599e3655bb398320ab27c9deed1aad508a963967815e626c21208f52158c2fc0796d0cc8186528efeb languageName: node linkType: hard @@ -8038,17 +7961,17 @@ __metadata: linkType: hard "ethers@npm:^6.12.0": - version: 6.13.5 - resolution: "ethers@npm:6.13.5" + version: 6.13.2 + resolution: "ethers@npm:6.13.2" dependencies: "@adraffy/ens-normalize": "npm:1.10.1" "@noble/curves": "npm:1.2.0" "@noble/hashes": "npm:1.3.2" - "@types/node": "npm:22.7.5" + "@types/node": "npm:18.15.13" aes-js: "npm:4.0.0-beta.5" - tslib: "npm:2.7.0" + tslib: "npm:2.4.0" ws: "npm:8.17.1" - checksum: 10/ccba21a83679fb6a7c3eb9d187593501565d140064f2db28057a64d6707678bacf2adf4555882c4814688246da73173560df81fd3361fd2f227b5d3c75cb8685 + checksum: 10/e611c2e2c5340982dfd1f004895f55abda11748a7edec9e6315226dec42d58aa61b827dd389ec904db5f9a244c475ae795e528da579251fdf62e914bde12809e languageName: node linkType: hard @@ -8226,7 +8149,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.2, fast-glob@npm:^3.3.2": +"fast-glob@npm:^3.2.2, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.2": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -8268,13 +8191,13 @@ __metadata: linkType: hard "fast-xml-parser@npm:^4.4.1": - version: 4.5.1 - resolution: "fast-xml-parser@npm:4.5.1" + version: 4.4.1 + resolution: "fast-xml-parser@npm:4.4.1" dependencies: strnum: "npm:^1.0.5" bin: fxparser: src/cli/cli.js - checksum: 10/17ce5908e798de1b6d12a39d26f04ac3b582ea9ce28f3a6e3b9c401edcb74790f28df84d75377608af53308ff8caad2b244ba1283cc4b5b4cf4cc7bd532a9983 + checksum: 10/0c05ab8703630d8c857fafadbd78d0020d3a8e54310c3842179cd4a0d9d97e96d209ce885e91241f4aa9dd8dfc2fd924a682741a423d65153cad34da2032ec44 languageName: node linkType: hard @@ -8286,11 +8209,11 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.18.0 - resolution: "fastq@npm:1.18.0" + version: 1.17.1 + resolution: "fastq@npm:1.17.1" dependencies: reusify: "npm:^1.0.4" - checksum: 10/c5b501333dc8f5d188d828ea162aad03ff5a81aed185b6d4a5078aaeae0a42babc34296d7af13ebce86401cccd93c9b7b3cbf61280821c5f20af233378b42fbb + checksum: 10/a443180068b527dd7b3a63dc7f2a47ceca2f3e97b9c00a1efe5538757e6cc4056a3526df94308075d7727561baf09ebaa5b67da8dcbddb913a021c5ae69d1f69 languageName: node linkType: hard @@ -8312,18 +8235,6 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.2": - version: 6.4.2 - resolution: "fdir@npm:6.4.2" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10/5ff80d1d2034e75cc68be175401c9f64c4938a6b2c1e9a0c27f2d211ffbe491fd86d29e4576825d9da8aff9bd465f0283427c2dddc11653457906c46d3bbc448 - languageName: node - linkType: hard - "figgy-pudding@npm:^3.5.1": version: 3.5.2 resolution: "figgy-pudding@npm:3.5.2" @@ -8382,38 +8293,37 @@ __metadata: linkType: hard "firebase@npm:^10.11.0": - version: 10.14.1 - resolution: "firebase@npm:10.14.1" - dependencies: - "@firebase/analytics": "npm:0.10.8" - "@firebase/analytics-compat": "npm:0.2.14" - "@firebase/app": "npm:0.10.13" - "@firebase/app-check": "npm:0.8.8" - "@firebase/app-check-compat": "npm:0.3.15" - "@firebase/app-compat": "npm:0.2.43" + version: 10.13.0 + resolution: "firebase@npm:10.13.0" + dependencies: + "@firebase/analytics": "npm:0.10.7" + "@firebase/analytics-compat": "npm:0.2.13" + "@firebase/app": "npm:0.10.9" + "@firebase/app-check": "npm:0.8.7" + "@firebase/app-check-compat": "npm:0.3.14" + "@firebase/app-compat": "npm:0.2.39" "@firebase/app-types": "npm:0.9.2" - "@firebase/auth": "npm:1.7.9" - "@firebase/auth-compat": "npm:0.5.14" - "@firebase/data-connect": "npm:0.1.0" - "@firebase/database": "npm:1.0.8" - "@firebase/database-compat": "npm:1.0.8" - "@firebase/firestore": "npm:4.7.3" - "@firebase/firestore-compat": "npm:0.3.38" - "@firebase/functions": "npm:0.11.8" - "@firebase/functions-compat": "npm:0.3.14" - "@firebase/installations": "npm:0.6.9" - "@firebase/installations-compat": "npm:0.2.9" - "@firebase/messaging": "npm:0.12.12" - "@firebase/messaging-compat": "npm:0.2.12" - "@firebase/performance": "npm:0.6.9" - "@firebase/performance-compat": "npm:0.2.9" - "@firebase/remote-config": "npm:0.4.9" - "@firebase/remote-config-compat": "npm:0.2.9" - "@firebase/storage": "npm:0.13.2" - "@firebase/storage-compat": "npm:0.3.12" - "@firebase/util": "npm:1.10.0" - "@firebase/vertexai-preview": "npm:0.0.4" - checksum: 10/1b2fd7b653f632d2bb0cf3b87e7eda0ae69d28b702a7de00d2a166c7985b8747ef9d15f7ac151847d242f91a1cb08c689d0a07197e8b80561ff1a679398bf9f8 + "@firebase/auth": "npm:1.7.7" + "@firebase/auth-compat": "npm:0.5.12" + "@firebase/database": "npm:1.0.7" + "@firebase/database-compat": "npm:1.0.7" + "@firebase/firestore": "npm:4.7.0" + "@firebase/firestore-compat": "npm:0.3.35" + "@firebase/functions": "npm:0.11.6" + "@firebase/functions-compat": "npm:0.3.12" + "@firebase/installations": "npm:0.6.8" + "@firebase/installations-compat": "npm:0.2.8" + "@firebase/messaging": "npm:0.12.10" + "@firebase/messaging-compat": "npm:0.2.10" + "@firebase/performance": "npm:0.6.8" + "@firebase/performance-compat": "npm:0.2.8" + "@firebase/remote-config": "npm:0.4.8" + "@firebase/remote-config-compat": "npm:0.2.8" + "@firebase/storage": "npm:0.13.0" + "@firebase/storage-compat": "npm:0.3.10" + "@firebase/util": "npm:1.9.7" + "@firebase/vertexai-preview": "npm:0.0.3" + checksum: 10/dd4d62acb3146cb96f88a98eead8a5a02ef42dc5f5a918bbf496f2f894a048ff9aef64b79f2dc8909995b7d3ad2d4d36d6a72add7c8ef3ee46cb811641fc572a languageName: node linkType: hard @@ -8428,19 +8338,19 @@ __metadata: linkType: hard "flatted@npm:^3.2.9": - version: 3.3.2 - resolution: "flatted@npm:3.3.2" - checksum: 10/ac3c159742e01d0e860a861164bcfd35bb567ccbebb8a0dd041e61cf3c64a435b917dd1e7ed1c380c2ebca85735fb16644485ec33665bc6aafc3b316aa1eed44 + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 10/7b8376061d5be6e0d3658bbab8bde587647f68797cf6bfeae9dea0e5137d9f27547ab92aaff3512dd9d1299086a6d61be98e9d48a56d17531b634f77faadbc49 languageName: node linkType: hard "follow-redirects@npm:^1.15.6": - version: 1.15.9 - resolution: "follow-redirects@npm:1.15.9" + version: 1.15.6 + resolution: "follow-redirects@npm:1.15.6" peerDependenciesMeta: debug: optional: true - checksum: 10/e3ab42d1097e90d28b913903841e6779eb969b62a64706a3eb983e894a5db000fbd89296f45f08885a0e54cd558ef62e81be1165da9be25a6c44920da10f424c + checksum: 10/70c7612c4cab18e546e36b991bbf8009a1a41cf85354afe04b113d1117569abf760269409cb3eb842d9f7b03d62826687086b081c566ea7b1e6613cf29030bf7 languageName: node linkType: hard @@ -8471,24 +8381,24 @@ __metadata: linkType: hard "form-data@npm:^3.0.0": - version: 3.0.2 - resolution: "form-data@npm:3.0.2" + version: 3.0.1 + resolution: "form-data@npm:3.0.1" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 10/b8d71d7149de5881c6c8ac75c03ac2e809b1b729399320cc41f59a63043fa34b95dfef5259212d6d902abb4916af48a7ca60ad5c035806ba8e3c7843dbaf3057 + checksum: 10/944b40ff63b9cb1ca7a97e70f72104c548e0b0263e3e817e49919015a0d687453086259b93005389896dbffd3777cccea2e67c51f4e827590e5979b14ff91bf7 languageName: node linkType: hard "form-data@npm:^4.0.0": - version: 4.0.1 - resolution: "form-data@npm:4.0.1" + version: 4.0.0 + resolution: "form-data@npm:4.0.0" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 10/6adb1cff557328bc6eb8a68da205f9ae44ab0e88d4d9237aaf91eed591ffc64f77411efb9016af7d87f23d0a038c45a788aa1c6634e51175c4efa36c2bc53774 + checksum: 10/7264aa760a8cf09482816d8300f1b6e2423de1b02bba612a136857413fdc96d7178298ced106817655facc6b89036c6e12ae31c9eb5bdc16aabf502ae8a5d805 languageName: node linkType: hard @@ -8575,21 +8485,16 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6": - version: 1.2.7 - resolution: "get-intrinsic@npm:1.2.7" +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" function-bind: "npm:^1.1.2" - get-proto: "npm:^1.0.0" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10/4f7149c9a826723f94c6d49f70bcb3df1d3f9213994fab3668f12f09fa72074681460fb29ebb6f135556ec6372992d63802386098791a8f09cfa6f27090fa67b + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10/85bbf4b234c3940edf8a41f4ecbd4e25ce78e5e6ad4e24ca2f77037d983b9ef943fd72f00f3ee97a49ec622a506b67db49c36246150377efcda1c9eb03e5f06d languageName: node linkType: hard @@ -8607,16 +8512,6 @@ __metadata: languageName: node linkType: hard -"get-proto@npm:^1.0.0": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/4fc96afdb58ced9a67558698b91433e6b037aaa6f1493af77498d7c85b141382cf223c0e5946f334fb328ee85dfe6edd06d218eaf09556f4bc4ec6005d7f5f7b - languageName: node - linkType: hard - "get-stdin@npm:^9.0.0": version: 9.0.0 resolution: "get-stdin@npm:9.0.0" @@ -8782,6 +8677,19 @@ __metadata: languageName: node linkType: hard +"globby@npm:^13.1.2": + version: 13.2.2 + resolution: "globby@npm:13.2.2" + dependencies: + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.3.0" + ignore: "npm:^5.2.4" + merge2: "npm:^1.4.1" + slash: "npm:^4.0.0" + checksum: 10/4494a9d2162a7e4d327988b26be66d8eab87d7f59a83219e74b065e2c3ced23698f68fb10482bf9337133819281803fb886d6ae06afbb2affa743623eb0b1949 + languageName: node + linkType: hard + "globrex@npm:^0.1.2": version: 0.1.2 resolution: "globrex@npm:0.1.2" @@ -8789,10 +8697,12 @@ __metadata: languageName: node linkType: hard -"gopd@npm:^1.0.1, gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10/94e296d69f92dc1c0768fcfeecfb3855582ab59a7c75e969d5f96ce50c3d201fd86d5a2857c22565764d5bb8a816c7b1e58f133ec318cd56274da36c5e3fb1a1 +"gopd@npm:^1.0.1": + version: 1.0.1 + resolution: "gopd@npm:1.0.1" + dependencies: + get-intrinsic: "npm:^1.1.3" + checksum: 10/5fbc7ad57b368ae4cd2f41214bd947b045c1a4be2f194a7be1778d71f8af9dbf4004221f3b6f23e30820eb0d052b4f819fe6ebe8221e2a3c6f0ee4ef173421ca languageName: node linkType: hard @@ -8852,14 +8762,21 @@ __metadata: languageName: node linkType: hard -"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10/959385c98696ebbca51e7534e0dc723ada325efa3475350951363cce216d27373e0259b63edb599f72eb94d6cde8577b4b2375f080b303947e560f85692834fa +"has-proto@npm:^1.0.1": + version: 1.0.3 + resolution: "has-proto@npm:1.0.3" + checksum: 10/0b67c2c94e3bea37db3e412e3c41f79d59259875e636ba471e94c009cdfb1fa82bf045deeffafc7dbb9c148e36cae6b467055aaa5d9fad4316e11b41e3ba551a + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.3": + version: 1.0.3 + resolution: "has-symbols@npm:1.0.3" + checksum: 10/464f97a8202a7690dadd026e6d73b1ceeddd60fe6acfd06151106f050303eaa75855aaa94969df8015c11ff7c505f196114d22f7386b4a471038da5874cf5e9b languageName: node linkType: hard -"has-tostringtag@npm:^1.0.2": +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" dependencies: @@ -8889,7 +8806,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.2": +"hasown@npm:^2.0.0, hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -8963,9 +8880,9 @@ __metadata: linkType: hard "http-parser-js@npm:>=0.5.1": - version: 0.5.9 - resolution: "http-parser-js@npm:0.5.9" - checksum: 10/65e6ef5e063b4f67c590bdd122b255e9b70c5bf3429718f8b72951fe98f4f968c55a58ec88cc96a11357a437d75c4af9302b8026c0b53c525065ff4eb0cd969e + version: 0.5.8 + resolution: "http-parser-js@npm:0.5.8" + checksum: 10/2a78a567ee6366dae0129d819b799dce1f95ec9732c5ab164a78ee69804ffb984abfa0660274e94e890fc54af93546eb9f12b6d10edbaed017e2d41c29b7cf29 languageName: node linkType: hard @@ -9011,12 +8928,12 @@ __metadata: linkType: hard "https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" dependencies: - agent-base: "npm:^7.1.2" + agent-base: "npm:^7.0.2" debug: "npm:4" - checksum: 10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13 + checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab languageName: node linkType: hard @@ -9217,12 +9134,12 @@ __metadata: linkType: hard "is-arguments@npm:^1.0.4": - version: 1.2.0 - resolution: "is-arguments@npm:1.2.0" + version: 1.1.1 + resolution: "is-arguments@npm:1.1.1" dependencies: - call-bound: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.2" - checksum: 10/471a8ef631b8ee8829c43a8ab05c081700c0e25180c73d19f3bf819c1a8448c426a9e8e601f278973eca68966384b16ceb78b8c63af795b099cd199ea5afc457 + call-bind: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.0" + checksum: 10/a170c7e26082e10de9be6e96d32ae3db4d5906194051b792e85fae3393b53cf2cb5b3557863e5c8ccbab55e2fd8f2f75aa643d437613f72052cf0356615c34be languageName: node linkType: hard @@ -9260,12 +9177,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.12.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" +"is-core-module@npm:^2.12.0, is-core-module@npm:^2.13.0": + version: 2.15.1 + resolution: "is-core-module@npm:2.15.1" dependencies: hasown: "npm:^2.0.2" - checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb + checksum: 10/77316d5891d5743854bcef2cd2f24c5458fb69fbc9705c12ca17d54a2017a67d0693bbf1ba8c77af376c0eef6bf6d1b27a4ab08e4db4e69914c3789bdf2ceec5 languageName: node linkType: hard @@ -9298,14 +9215,11 @@ __metadata: linkType: hard "is-generator-function@npm:^1.0.7": - version: 1.1.0 - resolution: "is-generator-function@npm:1.1.0" + version: 1.0.10 + resolution: "is-generator-function@npm:1.0.10" dependencies: - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.0" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10/5906ff51a856a5fbc6b90a90fce32040b0a6870da905f98818f1350f9acadfc9884f7c3dec833fce04b83dd883937b86a190b6593ede82e8b1af8b6c4ecf7cbd + has-tostringtag: "npm:^1.0.0" + checksum: 10/499a3ce6361064c3bd27fbff5c8000212d48506ebe1977842bbd7b3e708832d0deb1f4cc69186ece3640770e8c4f1287b24d99588a0b8058b2dbdd344bc1f47f languageName: node linkType: hard @@ -9363,18 +9277,6 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.2.1": - version: 1.2.1 - resolution: "is-regex@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10/c42b7efc5868a5c9a4d8e6d3e9816e8815c611b09535c00fead18a1138455c5cb5e1887f0023a467ad3f9c419d62ba4dc3d9ba8bafe55053914d6d6454a945d2 - languageName: node - linkType: hard - "is-ssh@npm:^1.4.0": version: 1.4.0 resolution: "is-ssh@npm:1.4.0" @@ -9399,11 +9301,11 @@ __metadata: linkType: hard "is-typed-array@npm:^1.1.3": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" + version: 1.1.13 + resolution: "is-typed-array@npm:1.1.13" dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10/e8cf60b9ea85667097a6ad68c209c9722cfe8c8edf04d6218366469e51944c5cc25bae45ffb845c23f811d262e4314d3b0168748eb16711aa34d12724cdf0735 + which-typed-array: "npm:^1.1.14" + checksum: 10/f850ba08286358b9a11aee6d93d371a45e3c59b5953549ee1c1a9a55ba5c1dd1bd9952488ae194ad8f32a9cf5e79c8fa5f0cc4d78c00720aa0bbcf238b38062d languageName: node linkType: hard @@ -10114,11 +10016,11 @@ __metadata: linkType: hard "jest-when@npm:^3.4.2": - version: 3.7.0 - resolution: "jest-when@npm:3.7.0" + version: 3.6.0 + resolution: "jest-when@npm:3.6.0" peerDependencies: jest: ">= 25" - checksum: 10/b5b88d077ed467aab220c71c885dbc5f448604f06e68f761ce9f479c99bb74e0dbf553d1cc980751d88401b034a578e1c44eec5e4095743b7586f02bb7c6313d + checksum: 10/0cb92738ccfa5711a685107f4437f18aefbe3cda120c912a9d49b612eeef03a910481ab40fe753fd42c4e617ffbb3d84c6bd66a76d963dac7f1ad9e9e5059359 languageName: node linkType: hard @@ -10379,9 +10281,9 @@ __metadata: linkType: hard "jsonschema@npm:^1.4.1": - version: 1.5.0 - resolution: "jsonschema@npm:1.5.0" - checksum: 10/46bf49b388ba922073bcb3c8d5e90af9d29fc8303dc866fd440182c88d6b4fd2807679fd39cdefb4113156d104ea47da9c0ff4bbcb0032c9fa29461cb1a92182 + version: 1.4.1 + resolution: "jsonschema@npm:1.4.1" + checksum: 10/d7a188da7a3100a2caa362b80e98666d46607b7a7153aac405b8e758132961911c6df02d444d4700691330874e21a62639f550e856b21ddd28423690751ca9c6 languageName: node linkType: hard @@ -10519,16 +10421,16 @@ __metadata: linkType: hard "loglevel@npm:^1.8.1": - version: 1.9.2 - resolution: "loglevel@npm:1.9.2" - checksum: 10/6153d8db308323f7ee20130bc40309e7a976c30a10379d8666b596d9c6441965c3e074c8d7ee3347fe5cfc059c0375b6f3e8a10b93d5b813cc5547f5aa412a29 + version: 1.9.1 + resolution: "loglevel@npm:1.9.1" + checksum: 10/863cbbcddf850a937482c604e2d11586574a5110b746bb49c7cc04739e01f6035f6db841d25377106dd330bca7142d74995f15a97c5f3ea0af86d9472d4a99f4 languageName: node linkType: hard "long@npm:^5.0.0": - version: 5.2.4 - resolution: "long@npm:5.2.4" - checksum: 10/c27c060a683d4d76dc48da12ded0ae49c610aaf10d028ec938829d7bebe916979dcc8b67ed71f8bf6d845a90151b66a9b741a3ee51ec874908e496c2a576697a + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 10/9167ec6947a825b827c30da169a7384eec6c0c9ec2f0b9c74da2e93d81159bbe39fb09c3f13dae9721d4b807ccfa09797a7dd1012f5d478e3e33ca3c78b608e6 languageName: node linkType: hard @@ -10573,19 +10475,19 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.2.1, luxon@npm:^3.5.0": +"luxon@npm:^3.2.1": version: 3.5.0 resolution: "luxon@npm:3.5.0" checksum: 10/48f86e6c1c96815139f8559456a3354a276ba79bcef0ae0d4f2172f7652f3ba2be2237b0e103b8ea0b79b47715354ac9fac04eb1db3485dcc72d5110491dd47f languageName: node linkType: hard -"magic-string@npm:^0.30.11": - version: 0.30.17 - resolution: "magic-string@npm:0.30.17" +"magic-string@npm:^0.30.10": + version: 0.30.11 + resolution: "magic-string@npm:0.30.11" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.5.0" - checksum: 10/2f71af2b0afd78c2e9012a29b066d2c8ba45a9cd0c8070f7fd72de982fb1c403b4e3afdb1dae00691d56885ede66b772ef6bedf765e02e3a7066208fe2fec4aa + checksum: 10/b784d2240252f5b1e755d487354ada4c672cbca16f045144f7185a75b059210e5fcca7be7be03ef1bac2ca754c4428b21d36ae64a9057ba429916f06b8c54eb2 languageName: node linkType: hard @@ -10625,25 +10527,6 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^14.0.3": - version: 14.0.3 - resolution: "make-fetch-happen@npm:14.0.3" - dependencies: - "@npmcli/agent": "npm:^3.0.0" - cacache: "npm:^19.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^4.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^5.0.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^12.0.0" - checksum: 10/fce0385840b6d86b735053dfe941edc2dd6468fda80fe74da1eeff10cbd82a75760f406194f2bc2fa85b99545b2bc1f84c08ddf994b21830775ba2d1a87e8bdf - languageName: node - linkType: hard - "makeerror@npm:1.0.12": version: 1.0.12 resolution: "makeerror@npm:1.0.12" @@ -10671,13 +10554,6 @@ __metadata: languageName: node linkType: hard -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10/11df2eda46d092a6035479632e1ec865b8134bdfc4bd9e571a656f4191525404f13a283a515938c3a8de934dbfd9c09674d9da9fa831e6eb7e22b50b197d2edd - languageName: node - linkType: hard - "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -10696,7 +10572,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 10/7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -10829,21 +10705,6 @@ __metadata: languageName: node linkType: hard -"minipass-fetch@npm:^4.0.0": - version: 4.0.0 - resolution: "minipass-fetch@npm:4.0.0" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^3.0.1" - dependenciesMeta: - encoding: - optional: true - checksum: 10/4b0772dbee77727b469dc5bfc371541d9aba1e243fbb46ddc1b9ff7efa4de4a4cf5ff3a359d6a3b3a460ca26df9ae67a9c93be26ab6417c225e49d63b52b2801 - languageName: node - linkType: hard - "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -10887,7 +10748,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 @@ -10904,16 +10765,6 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^3.0.1": - version: 3.0.1 - resolution: "minizlib@npm:3.0.1" - dependencies: - minipass: "npm:^7.0.4" - rimraf: "npm:^5.0.5" - checksum: 10/622cb85f51e5c206a080a62d20db0d7b4066f308cb6ce82a9644da112367c3416ae7062017e631eb7ac8588191cfa4a9a279b8651c399265202b298e98c4acef - languageName: node - linkType: hard - "mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" @@ -10923,15 +10774,6 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^3.0.1": - version: 3.0.1 - resolution: "mkdirp@npm:3.0.1" - bin: - mkdirp: dist/cjs/src/bin.js - checksum: 10/16fd79c28645759505914561e249b9a1f5fe3362279ad95487a4501e4467abeb714fd35b95307326b8fd03f3c7719065ef11a6f97b7285d7888306d1bd2232ba - languageName: node - linkType: hard - "ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -10940,9 +10782,9 @@ __metadata: linkType: hard "multiformats@npm:^13.1.0": - version: 13.3.1 - resolution: "multiformats@npm:13.3.1" - checksum: 10/2e529613d457590dffe212a658546f313c7c7296d240d952d2baee7ce0abb227116d784f05cf4d238ef0db7d72ad2c3d04ea3c6b9bfd20db805a092024ce8d7e + version: 13.2.2 + resolution: "multiformats@npm:13.2.2" + checksum: 10/6e673320e9b06d5fdbbf2bde0d3132f13fac94fb40f36d646265b5c38eba4a28c40a2c76b4efa0c1a23517fe87320e540e9ef7f28d71c1cc3239c91bf6770ce6 languageName: node linkType: hard @@ -10966,7 +10808,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.31, nanoid@npm:^3.3.8": +"nanoid@npm:^3.1.31, nanoid@npm:^3.3.7, nanoid@npm:^3.3.8": version: 3.3.8 resolution: "nanoid@npm:3.3.8" bin: @@ -10983,16 +10825,9 @@ __metadata: linkType: hard "negotiator@npm:^0.6.3": - version: 0.6.4 - resolution: "negotiator@npm:0.6.4" - checksum: 10/d98c04a136583afd055746168f1067d58ce4bfe6e4c73ca1d339567f81ea1f7e665b5bd1e81f4771c67b6c2ea89b21cb2adaea2b16058c7dc31317778f931dab - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 languageName: node linkType: hard @@ -11010,13 +10845,13 @@ __metadata: linkType: hard "nock@npm:^13.3.1": - version: 13.5.6 - resolution: "nock@npm:13.5.6" + version: 13.5.5 + resolution: "nock@npm:13.5.5" dependencies: debug: "npm:^4.1.0" json-stringify-safe: "npm:^5.0.1" propagate: "npm:^2.0.0" - checksum: 10/a57c265b75e5f7767e2f8baf058773cdbf357c31c5fea2761386ec03a008a657f9df921899fe2a9502773b47145b708863b32345aef529b3c45cba4019120f88 + checksum: 10/c19d7bf9654db056357a22b00127bb5606c1bbdff188a5b6c469825e580e31cd0cb0701bce8dd8b4876dbbd36a145fdb681fd69fd59308d6db4923ce8ab2439e languageName: node linkType: hard @@ -11053,19 +10888,19 @@ __metadata: linkType: hard "node-gyp-build@npm:^4.2.0": - version: 4.8.4 - resolution: "node-gyp-build@npm:4.8.4" + version: 4.8.1 + resolution: "node-gyp-build@npm:4.8.1" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: 10/6a7d62289d1afc419fc8fc9bd00aa4e554369e50ca0acbc215cb91446148b75ff7e2a3b53c2c5b2c09a39d416d69f3d3237937860373104b5fe429bf30ad9ac5 + checksum: 10/b9297770f96a92e5f2b854f3fd5e4bd418df81d7785a81ab60cec5cf2e5e72dc2c3319808978adc572cfa3885e6b12338cb5f4034bed2cab35f0d76a4b75ccdf languageName: node linkType: hard -"node-gyp@npm:^10.0.0": - version: 10.3.1 - resolution: "node-gyp@npm:10.3.1" +"node-gyp@npm:^10.0.0, node-gyp@npm:latest": + version: 10.2.0 + resolution: "node-gyp@npm:10.2.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" @@ -11079,27 +10914,7 @@ __metadata: which: "npm:^4.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10/d3004f648559e42d7ec8791ea75747fe8a163a6061c202e311e5d7a5f6266baa9a5f5c6fde7be563974c88b030c5d0855fd945364f52fcd230d2a2ceee7be80d - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 11.0.0 - resolution: "node-gyp@npm:11.0.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^14.0.3" - nopt: "npm:^8.0.0" - proc-log: "npm:^5.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.4.3" - which: "npm:^5.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/5d07430e887a906f85c7c6ed87e8facb7ecd4ce42d948a2438c471df2e24ae6af70f4def114ec1a03127988d164648dda8d75fe666f3c4b431e53856379fdf13 + checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe languageName: node linkType: hard @@ -11135,17 +10950,6 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^8.0.0": - version: 8.0.0 - resolution: "nopt@npm:8.0.0" - dependencies: - abbrev: "npm:^2.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/2d137f64b6f9331ec97047dd1cbbe4dcd9a61ceef4fd0f2252c0bbac1d69ba15671e6fd83a441328824b3ca78afe6ebe1694f12ebcd162b73a221582a06179ff - languageName: node - linkType: hard - "normalize-package-data@npm:^6.0.0": version: 6.0.2 resolution: "normalize-package-data@npm:6.0.2" @@ -11253,10 +11057,10 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.3": - version: 1.13.3 - resolution: "object-inspect@npm:1.13.3" - checksum: 10/14cb973d8381c69e14d7f1c8c75044eb4caf04c6dabcf40ca5c2ce42dc2073ae0bb2a9939eeca142b0c05215afaa1cd5534adb7c8879c32cba2576e045ed8368 +"object-inspect@npm:^1.13.1": + version: 1.13.2 + resolution: "object-inspect@npm:1.13.2" + checksum: 10/7ef65583b6397570a17c56f0c1841e0920e83900f2c94638927abb7b81ac08a19c7aae135bd9dcca96208cac0c7332b4650fb927f027b0cf92d71df2990d0561 languageName: node linkType: hard @@ -11278,16 +11082,14 @@ __metadata: linkType: hard "object.assign@npm:^4.1.4": - version: 4.1.7 - resolution: "object.assign@npm:4.1.7" + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" + call-bind: "npm:^1.0.5" define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" + has-symbols: "npm:^1.0.3" object-keys: "npm:^1.1.1" - checksum: 10/3fe28cdd779f2a728a9a66bd688679ba231a2b16646cd1e46b528fe7c947494387dda4bc189eff3417f3717ef4f0a8f2439347cf9a9aa3cef722fbfd9f615587 + checksum: 10/dbb22da4cda82e1658349ea62b80815f587b47131b3dd7a4ab7f84190ab31d206bbd8fe7e26ae3220c55b65725ac4529825f6142154211220302aa6b1518045d languageName: node linkType: hard @@ -11384,13 +11186,6 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^7.0.2": - version: 7.0.3 - resolution: "p-map@npm:7.0.3" - checksum: 10/2ef48ccfc6dd387253d71bf502604f7893ed62090b2c9d73387f10006c342606b05233da0e4f29388227b61eb5aeface6197e166520c465c234552eeab2fe633 - languageName: node - linkType: hard - "p-throttle@npm:^4.1.1": version: 4.1.1 resolution: "p-throttle@npm:4.1.1" @@ -11406,9 +11201,9 @@ __metadata: linkType: hard "package-json-from-dist@npm:^1.0.0": - version: 1.0.1 - resolution: "package-json-from-dist@npm:1.0.1" - checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea languageName: node linkType: hard @@ -11563,7 +11358,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -11577,13 +11372,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^4.0.2": - version: 4.0.2 - resolution: "picomatch@npm:4.0.2" - checksum: 10/ce617b8da36797d09c0baacb96ca8a44460452c89362d7cb8f70ca46b4158ba8bc3606912de7c818eb4a939f7f9015cef3c766ec8a0c6bfc725fdc078e39c717 - languageName: node - linkType: hard - "pify@npm:^5.0.0": version: 5.0.0 resolution: "pify@npm:5.0.0" @@ -11630,14 +11418,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.48": - version: 8.5.1 - resolution: "postcss@npm:8.5.1" +"postcss@npm:^8.4.40": + version: 8.4.41 + resolution: "postcss@npm:8.4.41" dependencies: - nanoid: "npm:^3.3.8" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10/1fbd28753143f7f03e4604813639918182b15343c7ad0f4e72f3875fc2cc0b8494c887f55dc05008fad5fbf1e1e908ce2edbbce364a91f84dcefb71edf7cd31d + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.1" + source-map-js: "npm:^1.2.0" + checksum: 10/6e6176c2407eff60493ca60a706c6b7def20a722c3adda94ea1ece38345eb99964191336fd62b62652279cec6938e79e0b1e1d477142c8d3516e7a725a74ee37 languageName: node linkType: hard @@ -11658,17 +11446,17 @@ __metadata: linkType: hard "prettier-plugin-packagejson@npm:^2.4.5": - version: 2.5.7 - resolution: "prettier-plugin-packagejson@npm:2.5.7" + version: 2.5.2 + resolution: "prettier-plugin-packagejson@npm:2.5.2" dependencies: - sort-package-json: "npm:2.13.0" - synckit: "npm:0.9.2" + sort-package-json: "npm:2.10.1" + synckit: "npm:0.9.1" peerDependencies: prettier: ">= 1.16.0" peerDependenciesMeta: prettier: optional: true - checksum: 10/eca337657660e706134a1509053c39a88249965ff8ec692074c24ad7c2234b878d48c0ccb803e0827a47e676cbeb5ce7845e21f9fbe2c9bdf12e2565b91d0515 + checksum: 10/f280d69327a468cd104c72a81134258d3573e56d697a88a5c4498c8d02cecda9a27d9eb3f1d29cc726491782eb3f279c9d41ecf8364a197e20b239c5ccfd0269 languageName: node linkType: hard @@ -11719,13 +11507,6 @@ __metadata: languageName: node linkType: hard -"proc-log@npm:^5.0.0": - version: 5.0.0 - resolution: "proc-log@npm:5.0.0" - checksum: 10/35610bdb0177d3ab5d35f8827a429fb1dc2518d9e639f2151ac9007f01a061c30e0c635a970c9b00c39102216160f6ec54b62377c92fac3b7bfc2ad4b98d195c - languageName: node - linkType: hard - "process@npm:^0.11.10": version: 0.11.10 resolution: "process@npm:0.11.10" @@ -11812,11 +11593,9 @@ __metadata: linkType: hard "psl@npm:^1.1.33": - version: 1.15.0 - resolution: "psl@npm:1.15.0" - dependencies: - punycode: "npm:^2.3.1" - checksum: 10/5e7467eb5196eb7900d156783d12907d445c0122f76c73203ce96b148a6ccf8c5450cc805887ffada38ff92d634afcf33720c24053cb01d5b6598d1c913c5caf + version: 1.9.0 + resolution: "psl@npm:1.9.0" + checksum: 10/d07879d4bfd0ac74796306a8e5a36a93cfb9c4f4e8ee8e63fbb909066c192fe1008cd8f12abd8ba2f62ca28247949a20c8fb32e1d18831d9e71285a1569720f9 languageName: node linkType: hard @@ -11837,7 +11616,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 @@ -11845,11 +11624,11 @@ __metadata: linkType: hard "qs@npm:^6.11.2": - version: 6.14.0 - resolution: "qs@npm:6.14.0" + version: 6.13.0 + resolution: "qs@npm:6.13.0" dependencies: - side-channel: "npm:^1.1.0" - checksum: 10/a60e49bbd51c935a8a4759e7505677b122e23bf392d6535b8fc31c1e447acba2c901235ecb192764013cd2781723dc1f61978b5fdd93cc31d7043d31cdc01974 + side-channel: "npm:^1.0.6" + checksum: 10/f548b376e685553d12e461409f0d6e5c59ec7c7d76f308e2a888fd9db3e0c5e89902bedd0754db3a9038eda5f27da2331a6f019c8517dc5e0a16b3c9a6e9cef8 languageName: node linkType: hard @@ -11969,15 +11748,15 @@ __metadata: linkType: hard "readable-stream@npm:^3.6.2 || ^4.4.2": - version: 4.7.0 - resolution: "readable-stream@npm:4.7.0" + version: 4.5.2 + resolution: "readable-stream@npm:4.5.2" dependencies: abort-controller: "npm:^3.0.0" buffer: "npm:^6.0.3" events: "npm:^3.3.0" process: "npm:^0.11.10" string_decoder: "npm:^1.3.0" - checksum: 10/bdf096c8ff59452ce5d08f13da9597f9fcfe400b4facfaa88e74ec057e5ad1fdfa140ffe28e5ed806cf4d2055f0b812806e962bca91dce31bc4cef08e53be3a4 + checksum: 10/01b128a559c5fd76a898495f858cf0a8839f135e6a69e3409f986e88460134791657eb46a2ff16826f331682a3c4d0c5a75cef5e52ef259711021ba52b1c2e82 languageName: node linkType: hard @@ -12102,7 +11881,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.22.8": +"resolve@npm:1.22.8, resolve@npm:^1.20.0, resolve@npm:^1.22.3, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -12115,20 +11894,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.20.0, resolve@npm:^1.22.3, resolve@npm:^1.22.4": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A1.22.8#optional!builtin": +"resolve@patch:resolve@npm%3A1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.3#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -12141,19 +11907,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.3#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a - languageName: node - linkType: hard - "responselike@npm:^2.0.0": version: 2.0.1 resolution: "responselike@npm:2.0.1" @@ -12262,7 +12015,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -12276,17 +12029,6 @@ __metadata: languageName: node linkType: hard -"safe-regex-test@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex-test@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-regex: "npm:^1.2.1" - checksum: 10/ebdb61f305bf4756a5b023ad86067df5a11b26898573afe9e52a548a63c3bd594825d9b0e2dde2eb3c94e57e0e04ac9929d4107c394f7b8e56a4613bed46c69a - languageName: node - linkType: hard - "safe-stable-stringify@npm:^2.4.3": version: 2.5.0 resolution: "safe-stable-stringify@npm:2.5.0" @@ -12365,15 +12107,15 @@ __metadata: linkType: hard "ses@npm:^1.1.0": - version: 1.10.0 - resolution: "ses@npm:1.10.0" + version: 1.7.0 + resolution: "ses@npm:1.7.0" dependencies: - "@endo/env-options": "npm:^1.1.8" - checksum: 10/57073350cab333e3c4516e8ea09e1ddd2f81fdd954dc48798548d098550d1da8bb3266def0461a34a4e11c0a1027bde03e05f2ac5feb512ff3fc33dd327a9bb2 + "@endo/env-options": "npm:^1.1.5" + checksum: 10/8d1227fadcd06653d1b49083c067ae07e55164af984c9e8b393238fbbd315f47216472e3ac65a78638955f3f1a2537e9c9865f0ab142639a6862b902cb1cf6f2 languageName: node linkType: hard -"set-function-length@npm:^1.2.2": +"set-function-length@npm:^1.2.1": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" dependencies: @@ -12455,51 +12197,15 @@ __metadata: languageName: node linkType: hard -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10/603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" +"side-channel@npm:^1.0.6": + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" dependencies: + call-bind: "npm:^1.0.7" es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba + get-intrinsic: "npm:^1.2.4" + object-inspect: "npm:^1.13.1" + checksum: 10/eb10944f38cebad8ad643dd02657592fa41273ce15b8bfa928d3291aff2d30c20ff777cfe908f76ccc4551ace2d1245822fdc576657cce40e9066c638ca8fa4d languageName: node linkType: hard @@ -12575,6 +12281,13 @@ __metadata: languageName: node linkType: hard +"slash@npm:^4.0.0": + version: 4.0.0 + resolution: "slash@npm:4.0.0" + checksum: 10/da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d + languageName: node + linkType: hard + "slashes@npm:^3.0.12": version: 3.0.12 resolution: "slashes@npm:3.0.12" @@ -12601,13 +12314,13 @@ __metadata: linkType: hard "socks-proxy-agent@npm:^8.0.3": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" + version: 8.0.4 + resolution: "socks-proxy-agent@npm:8.0.4" dependencies: - agent-base: "npm:^7.1.2" + agent-base: "npm:^7.1.1" debug: "npm:^4.3.4" socks: "npm:^2.8.3" - checksum: 10/ee99e1dacab0985b52cbe5a75640be6e604135e9489ebdc3048635d186012fbaecc20fbbe04b177dee434c319ba20f09b3e7dfefb7d932466c0d707744eac05c + checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7 languageName: node linkType: hard @@ -12628,28 +12341,28 @@ __metadata: languageName: node linkType: hard -"sort-package-json@npm:2.13.0": - version: 2.13.0 - resolution: "sort-package-json@npm:2.13.0" +"sort-package-json@npm:2.10.1": + version: 2.10.1 + resolution: "sort-package-json@npm:2.10.1" dependencies: detect-indent: "npm:^7.0.1" detect-newline: "npm:^4.0.0" get-stdin: "npm:^9.0.0" git-hooks-list: "npm:^3.0.0" + globby: "npm:^13.1.2" is-plain-obj: "npm:^4.1.0" semver: "npm:^7.6.0" sort-object-keys: "npm:^1.1.3" - tinyglobby: "npm:^0.2.9" bin: sort-package-json: cli.js - checksum: 10/06081222ca6a0affddb613d6ee703012aba460b3b41930a229b1ba222f5829fc5dba996b69e229c198164112600455dc3178bbd7819f80c33503dbea61f67fac + checksum: 10/3a08cb9227c244d51bfb0eaaa5a9ea82fd3c96ea299c040365700b3f445d46a98411df4237f4e3c96ba67be4dcd53931747eab3b799f0335d278b36d64f1061d languageName: node linkType: hard -"source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1": - version: 1.2.1 - resolution: "source-map-js@npm:1.2.1" - checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3 +"source-map-js@npm:^1.2.0": + version: 1.2.0 + resolution: "source-map-js@npm:1.2.0" + checksum: 10/74f331cfd2d121c50790c8dd6d3c9de6be21926de80583b23b37029b0f37aefc3e019fa91f9a10a5e120c08135297e1ecf312d561459c45908cb1e0e365f49e5 languageName: node linkType: hard @@ -12715,9 +12428,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.21 - resolution: "spdx-license-ids@npm:3.0.21" - checksum: 10/17a033b4c3485f081fc9faa1729dde8782a85d9131b156f2397c71256c2e1663132857d3cba1457c4965f179a4dcf1b69458a31e9d3d0c766d057ef0e3a0b4f2 + version: 3.0.20 + resolution: "spdx-license-ids@npm:3.0.20" + checksum: 10/30e566ea74b04232c64819d1f5313c00d92e9c73d054541650331fc794499b3bcc4991bcd90fa3c2fc4d040006f58f63104706255266e87a9d452e6574afc60c languageName: node linkType: hard @@ -12744,15 +12457,6 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^12.0.0": - version: 12.0.0 - resolution: "ssri@npm:12.0.0" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/7024c1a6e39b3f18aa8f1c8290e884fe91b0f9ca5a6c6d410544daad54de0ba664db879afe16412e187c6c292fd60b937f047ee44292e5c2af2dcc6d8e1a9b48 - languageName: node - linkType: hard - "ssri@npm:^6.0.1": version: 6.0.2 resolution: "ssri@npm:6.0.2" @@ -12779,8 +12483,8 @@ __metadata: linkType: hard "streamx@npm:^2.15.0": - version: 2.21.1 - resolution: "streamx@npm:2.21.1" + version: 2.19.0 + resolution: "streamx@npm:2.19.0" dependencies: bare-events: "npm:^2.2.0" fast-fifo: "npm:^1.3.2" @@ -12789,7 +12493,7 @@ __metadata: dependenciesMeta: bare-events: optional: true - checksum: 10/d61ee82033f8b900226e2405aeb683de5f51a68ded1d40198d548cd9a7b2e47b7706442c9142bbc7fc59874f03063ee41ddf9e8667e63186b507b2e6b394ac28 + checksum: 10/3e57a12402200cce347bd0658b5e7ef14a41636341256d2a9f43100e5c4f5d82166a4df77aef92082686150805a1b14f74370f3c96b4ed3d6d9889da1e3b3c21 languageName: node linkType: hard @@ -12938,7 +12642,17 @@ __metadata: languageName: node linkType: hard -"synckit@npm:0.9.2, synckit@npm:^0.9.1": +"synckit@npm:0.9.1": + version: 0.9.1 + resolution: "synckit@npm:0.9.1" + dependencies: + "@pkgr/core": "npm:^0.1.0" + tslib: "npm:^2.6.2" + checksum: 10/bff3903976baf8b699b5483228116d70223781a93b17c70e685c277ee960cdfd1a09cb5a741e6a9ec35e2428f14f4664baec41ccc99a598f267608b2a54f529b + languageName: node + linkType: hard + +"synckit@npm:^0.9.1": version: 0.9.2 resolution: "synckit@npm:0.9.2" dependencies: @@ -12993,20 +12707,6 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.4.3": - version: 7.4.3 - resolution: "tar@npm:7.4.3" - dependencies: - "@isaacs/fs-minipass": "npm:^4.0.0" - chownr: "npm:^3.0.0" - minipass: "npm:^7.1.2" - minizlib: "npm:^3.0.1" - mkdirp: "npm:^3.0.1" - yallist: "npm:^5.0.0" - checksum: 10/12a2a4fc6dee23e07cc47f1aeb3a14a1afd3f16397e1350036a8f4cdfee8dcac7ef5978337a4e7b2ac2c27a9a6d46388fc2088ea7c80cb6878c814b1425f8ecf - languageName: node - linkType: hard - "tau-prolog@npm:^0.2.66": version: 0.2.81 resolution: "tau-prolog@npm:0.2.81" @@ -13039,11 +12739,11 @@ __metadata: linkType: hard "text-decoder@npm:^1.1.0": - version: 1.2.3 - resolution: "text-decoder@npm:1.2.3" + version: 1.1.1 + resolution: "text-decoder@npm:1.1.1" dependencies: b4a: "npm:^1.6.4" - checksum: 10/bcdec33c0f070aeac38e46e4cafdcd567a58473ed308bdf75260bfbd8f7dc76acbc0b13226afaec4a169d0cb44cec2ab89c57b6395ccf02e941eaebbe19e124a + checksum: 10/c6981b93850daeafc8bd1dbd8f984d4fb2d14632f450de0892692b5bbee2d2f4cbef8a807142527370649fd357f58491ede4915d43669eca624cb52b8dd247b6 languageName: node linkType: hard @@ -13064,16 +12764,6 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.9": - version: 0.2.10 - resolution: "tinyglobby@npm:0.2.10" - dependencies: - fdir: "npm:^6.4.2" - picomatch: "npm:^4.0.2" - checksum: 10/10c976866d849702edc47fc3fef27d63f074c40f75ef17171ecc1452967900699fa1e62373681dd58e673ddff2e3f6094bcd0a2101e3e4b30f4c2b9da41397f2 - languageName: node - linkType: hard - "tinylogic@npm:^2.0.0": version: 2.0.0 resolution: "tinylogic@npm:2.0.0" @@ -13212,14 +12902,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.7.0": - version: 2.7.0 - resolution: "tslib@npm:2.7.0" - checksum: 10/9a5b47ddac65874fa011c20ff76db69f97cf90c78cff5934799ab8894a5342db2d17b4e7613a087046bc1d133d21547ddff87ac558abeec31ffa929c88b7fce6 +"tslib@npm:2.4.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 10/d8379e68b36caf082c1905ec25d17df8261e1d68ddc1abfd6c91158a064f6e4402039ae7c02cf4c81d12e3a2a2c7cd8ea2f57b233eb80136a2e3e7279daf2911 languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3": +"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 @@ -13270,13 +12960,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:4.30.0": - version: 4.30.0 - resolution: "type-fest@npm:4.30.0" - checksum: 10/46c733df4feb87dfd281fba4fa3913dc38b45136be35adffbcef95e13414105a4669476c1f8686680b9c98e59ed5dc85efe42caf67adbaa04f48dfc41f8330fa - languageName: node - linkType: hard - "type-fest@npm:^0.12.0": version: 0.12.0 resolution: "type-fest@npm:0.12.0" @@ -13299,9 +12982,9 @@ __metadata: linkType: hard "type-fest@npm:^4.0.0": - version: 4.32.0 - resolution: "type-fest@npm:4.32.0" - checksum: 10/7cee33a2d82c992e97e85eca4016a7dd62239fc6f95a7f86d46671900cad594eda832d97a1d4231d3bb2ed7ff5144c5f3cf4644e1f722faa4e6decef0c5276ca + version: 4.25.0 + resolution: "type-fest@npm:4.25.0" + checksum: 10/16ddf51dbfeef45e6f0a139c16f06d6cd05b61be76b048c41e79997f150a66422219d7ec10a2717ab926505402d59b1ddc8560f5f6c245e1b8a35971c2f1b754 languageName: node linkType: hard @@ -13347,16 +13030,16 @@ __metadata: linkType: hard "typescript-eslint@npm:^8.7.0": - version: 8.20.0 - resolution: "typescript-eslint@npm:8.20.0" + version: 8.19.1 + resolution: "typescript-eslint@npm:8.19.1" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.20.0" - "@typescript-eslint/parser": "npm:8.20.0" - "@typescript-eslint/utils": "npm:8.20.0" + "@typescript-eslint/eslint-plugin": "npm:8.19.1" + "@typescript-eslint/parser": "npm:8.19.1" + "@typescript-eslint/utils": "npm:8.19.1" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.8.0" - checksum: 10/5d72ec36d9a6a519cedb003af28bdad37560999a6f8a126193098ff403d6cc6947f3f27d09171d446bc62e43a1aeb00563ce1adfc85014a011993bfa2c95a20f + checksum: 10/3e7861bcd47c0bea962662d5f18a9f9214270057c082f2e3839ee2f681a42018395755216005d2408447de5b96892b6a18cc794daf8663bba1753def48e6756c languageName: node linkType: hard @@ -13394,17 +13077,12 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.20.0": - version: 6.20.0 - resolution: "undici-types@npm:6.20.0" - checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe - languageName: node - linkType: hard - -"undici@npm:6.19.7": - version: 6.19.7 - resolution: "undici@npm:6.19.7" - checksum: 10/77fb8b0377388f6dba8244b015841318d621031211b4f3c2273d809304b77ec44adeba4b89dfd6708bdc044190e18f068e5b231882ef15d057d4624e46f544e3 +"undici@npm:5.28.4": + version: 5.28.4 + resolution: "undici@npm:5.28.4" + dependencies: + "@fastify/busboy": "npm:^2.0.0" + checksum: 10/a666a9f5ac4270c659fafc33d78b6b5039a0adbae3e28f934774c85dcc66ea91da907896f12b414bd6f578508b44d5dc206fa636afa0e49a4e1c9e99831ff065 languageName: node linkType: hard @@ -13417,15 +13095,6 @@ __metadata: languageName: node linkType: hard -"unique-filename@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-filename@npm:4.0.0" - dependencies: - unique-slug: "npm:^5.0.0" - checksum: 10/6a62094fcac286b9ec39edbd1f8f64ff92383baa430af303dfed1ffda5e47a08a6b316408554abfddd9730c78b6106bef4ca4d02c1231a735ddd56ced77573df - languageName: node - linkType: hard - "unique-slug@npm:^4.0.0": version: 4.0.0 resolution: "unique-slug@npm:4.0.0" @@ -13435,15 +13104,6 @@ __metadata: languageName: node linkType: hard -"unique-slug@npm:^5.0.0": - version: 5.0.0 - resolution: "unique-slug@npm:5.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/beafdf3d6f44990e0a5ce560f8f881b4ee811be70b6ba0db25298c31c8cf525ed963572b48cd03be1c1349084f9e339be4241666d7cf1ebdad20598d3c652b27 - languageName: node - linkType: hard - "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" @@ -13725,17 +13385,16 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.2": - version: 1.1.18 - resolution: "which-typed-array@npm:1.1.18" +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.2": + version: 1.1.15 + resolution: "which-typed-array@npm:1.1.15" dependencies: available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" + call-bind: "npm:^1.0.7" for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" + gopd: "npm:^1.0.1" has-tostringtag: "npm:^1.0.2" - checksum: 10/11eed801b2bd08cdbaecb17aff381e0fb03526532f61acc06e6c7b9370e08062c33763a51f27825f13fdf34aabd0df6104007f4e8f96e6eaef7db0ce17a26d6e + checksum: 10/c3b6a99beadc971baa53c3ee5b749f2b9bdfa3b3b9a70650dd8511a48b61d877288b498d424712e9991d16019633086bd8b5923369460d93463c5825fa36c448 languageName: node linkType: hard @@ -13783,17 +13442,6 @@ __metadata: languageName: node linkType: hard -"which@npm:^5.0.0": - version: 5.0.0 - resolution: "which@npm:5.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10/6ec99e89ba32c7e748b8a3144e64bfc74aa63e2b2eacbb61a0060ad0b961eb1a632b08fb1de067ed59b002cec3e21de18299216ebf2325ef0f78e0f121e14e90 - languageName: node - linkType: hard - "widest-line@npm:^3.1.0": version: 3.1.0 resolution: "widest-line@npm:3.1.0" @@ -13961,13 +13609,6 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^5.0.0": - version: 5.0.0 - resolution: "yallist@npm:5.0.0" - checksum: 10/1884d272d485845ad04759a255c71775db0fac56308764b4c77ea56a20d56679fad340213054c8c9c9c26fcfd4c4b2a90df993b7e0aaf3cdb73c618d1d1a802a - languageName: node - linkType: hard - "yaml@npm:^1.10.0": version: 1.10.2 resolution: "yaml@npm:1.10.2" @@ -13976,11 +13617,11 @@ __metadata: linkType: hard "yaml@npm:^2.2.2": - version: 2.7.0 - resolution: "yaml@npm:2.7.0" + version: 2.5.0 + resolution: "yaml@npm:2.5.0" bin: yaml: bin.mjs - checksum: 10/c8c314c62fbd49244a6a51b06482f6d495b37ab10fa685fcafa1bbaae7841b7233ee7d12cab087bcca5a0b28adc92868b6e437322276430c28d00f1c1732eeec + checksum: 10/72e903fdbe3742058885205db4a6c9ff38e5f497f4e05e631264f7756083c05e7d10dfb5e4ce9d7a95de95338f9b20d19dd0b91c60c65f7d7608b6b3929820ad languageName: node linkType: hard From 24f17e0ef9605799019d26f77480d8b919c5491d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 16 Jan 2025 10:26:17 -0800 Subject: [PATCH 138/146] add MiddlewareManager middleware eth_subscribe eth_unsubscribe catch --- .../MultichainMiddlewareManager.test.ts | 65 +++++++++++++++++++ .../MultichainMiddlewareManager.ts | 6 ++ 2 files changed, 71 insertions(+) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index ac65138b2ec..21b143ebafa 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -1,3 +1,5 @@ +import { rpcErrors } from '@metamask/rpc-errors'; + import type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager'; import { MultichainMiddlewareManager } from './MultichainMiddlewareManager'; @@ -41,6 +43,69 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); + it('should add middleware and call next if if no middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should add middleware and return error if if no middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).toHaveBeenCalledWith(rpcErrors.methodNotFound()); + }); + + it('should add middleware and return error if if no middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'eth_unsubscribe', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).toHaveBeenCalledWith(rpcErrors.methodNotFound()); + }); + it('should remove middleware by origin and tabId when the multiplexing middleware is destroyed and the middleware has no destroy function', async () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index 9ae20e668f8..ee342b9cff9 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -2,6 +2,7 @@ import type { JsonRpcEngineEndCallback, JsonRpcEngineNextCallback, } from '@metamask/json-rpc-engine'; +import { rpcErrors } from '@metamask/rpc-errors'; import type { Json, JsonRpcRequest, @@ -125,6 +126,11 @@ export class MultichainMiddlewareManager { if (middlewareEntry) { middlewareEntry.middleware(req, res, next, end); + } else if (['eth_subscribe', 'eth_unsubscribe'].includes(req.method)) { + // TODO: Temporary safety guard to prevent requests with these methods + // from being forwarded to the RPC endpoint even though this scenario + // should not be possible. + return end(rpcErrors.methodNotFound()); } else { return next(); } From 7d16401f9f3ebc271b222d27b70ed4555e5d442e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 16 Jan 2025 10:42:31 -0800 Subject: [PATCH 139/146] Only pass request to middleware if request is eth_subscribe or unsubscirbe --- .../MultichainMiddlewareManager.test.ts | 77 +++++++++++++++++-- .../MultichainMiddlewareManager.ts | 19 +++-- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 21b143ebafa..4da0091e91a 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -8,7 +8,7 @@ const origin = 'example.com'; const tabId = 123; describe('MultichainMiddlewareManager', () => { - it('should add middleware and get called for the scope, origin, and tabId', () => { + it('should add middleware and get called for the scope, origin, and tabId if request is "eth_subscribe', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; multichainMiddlewareManager.addMiddleware({ @@ -28,13 +28,48 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, ); expect(middlewareSpy).toHaveBeenCalledWith( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should add middleware and get called for the scope, origin, and tabId if request is "eth_unsubscribe', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'eth_unsubscribe', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).toHaveBeenCalledWith( + { jsonrpc: '2.0' as const, id: 0, method: 'eth_unsubscribe', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -43,7 +78,37 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and call next if if no middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { + it('should add middleware and call next if called for the scope, origin, and tabId but request is not "eth_subscribe" or "eth_unsubscribe"', () => { + const multichainMiddlewareManager = new MultichainMiddlewareManager(); + const middlewareSpy = jest.fn() as unknown as ExtendedJsonRpcMiddleware; + multichainMiddlewareManager.addMiddleware({ + scope, + origin, + tabId, + middleware: middlewareSpy, + }); + + const middleware = + multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( + origin, + 123, + ); + + const nextSpy = jest.fn(); + const endSpy = jest.fn(); + + middleware( + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0', id: 0 }, + nextSpy, + endSpy, + ); + expect(middlewareSpy).not.toHaveBeenCalled() + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); + }); + + it('should add middleware and call next ifno middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( @@ -64,7 +129,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and return error if if no middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { + it('should add middleware and return error ifno middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( @@ -85,7 +150,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).toHaveBeenCalledWith(rpcErrors.methodNotFound()); }); - it('should add middleware and return error if if no middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { + it('should add middleware and return error ifno middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts index ee342b9cff9..8b056ea4f32 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.ts @@ -30,6 +30,9 @@ type MiddlewareEntry = MiddlewareKey & { middleware: ExtendedJsonRpcMiddleware; }; +// Methods related to eth_subscriptions +const SubscriptionMethods = ['eth_subscribe', 'eth_unsubscribe']; + /** * A helper that facilates registering and calling of provided middleware instances * in the RPC pipeline based on the incoming request's scope, origin, and tabId. @@ -124,13 +127,15 @@ export class MultichainMiddlewareManager { tabId, }); - if (middlewareEntry) { - middlewareEntry.middleware(req, res, next, end); - } else if (['eth_subscribe', 'eth_unsubscribe'].includes(req.method)) { - // TODO: Temporary safety guard to prevent requests with these methods - // from being forwarded to the RPC endpoint even though this scenario - // should not be possible. - return end(rpcErrors.methodNotFound()); + if (SubscriptionMethods.includes(req.method)) { + if (middlewareEntry) { + middlewareEntry.middleware(req, res, next, end); + } else { + // TODO: Temporary safety guard to prevent requests with these methods + // from being forwarded to the RPC endpoint even though this scenario + // should not be possible. + return end(rpcErrors.methodNotFound()); + } } else { return next(); } From cc369d6567ab2d4fd9232a7a752a8c161a20fc07 Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 16 Jan 2025 10:58:27 -0800 Subject: [PATCH 140/146] Update packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts Co-authored-by: Frederik Bolding --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 4da0091e91a..a8fa288aa82 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -150,7 +150,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).toHaveBeenCalledWith(rpcErrors.methodNotFound()); }); - it('should add middleware and return error ifno middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { + it('should add middleware and return error if no middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( From 3cb0fe70c4278eb3daee51b90c427fa5fd7f7e6d Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 16 Jan 2025 10:58:35 -0800 Subject: [PATCH 141/146] Update packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts Co-authored-by: Frederik Bolding --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index a8fa288aa82..90907ac578f 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -108,7 +108,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and call next ifno middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { + it('should add middleware and call next if no middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( From 718b553eafb7cc164de495fed9fdc8056965db48 Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 16 Jan 2025 10:58:41 -0800 Subject: [PATCH 142/146] Update packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts Co-authored-by: Frederik Bolding --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 90907ac578f..50ca97b339d 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -129,7 +129,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and return error ifno middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { + it('should add middleware and return error if no middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( From 4776860c005a14bcdbfdc97750ae42c0290827f7 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 16 Jan 2025 10:59:59 -0800 Subject: [PATCH 143/146] fix should remove tests --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 4da0091e91a..2c086c11583 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -333,7 +333,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, @@ -365,7 +365,7 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, From af0d8c72ff0531965448618e1855deea649e7ec7 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 17 Jan 2025 11:46:04 -0800 Subject: [PATCH 144/146] fix MultichainMiddlewareManager spec --- .../src/middlewares/MultichainMiddlewareManager.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index bce2ca96179..9faa596ab79 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -339,8 +339,8 @@ describe('MultichainMiddlewareManager', () => { endSpy, ); expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).toHaveBeenCalled(); }); it('should remove middleware by origin and tabId', () => { @@ -371,7 +371,7 @@ describe('MultichainMiddlewareManager', () => { endSpy, ); expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).toHaveBeenCalled(); - expect(endSpy).not.toHaveBeenCalled(); + expect(nextSpy).not.toHaveBeenCalled(); + expect(endSpy).toHaveBeenCalled(); }); }); From 237eb5902cb9c40eb062d8ff6492f82a003af817 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 17 Jan 2025 15:33:03 -0800 Subject: [PATCH 145/146] fix MultichainMiddlewareManager spec and scenario names --- .../MultichainMiddlewareManager.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts index 9faa596ab79..afb57036e8c 100644 --- a/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts +++ b/packages/multichain/src/middlewares/MultichainMiddlewareManager.test.ts @@ -108,7 +108,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and call next if no middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { + it('call next if no middleware exists for scope, origin, and tabId and request is not "eth_subscribe" or "eth_unsubscribe', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( @@ -129,7 +129,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).not.toHaveBeenCalled(); }); - it('should add middleware and return error if no middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { + it('return error if no middleware exists for scope, origin, and tabId and request is "eth_subscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( @@ -150,7 +150,7 @@ describe('MultichainMiddlewareManager', () => { expect(endSpy).toHaveBeenCalledWith(rpcErrors.methodNotFound()); }); - it('should add middleware and return error if no middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { + it('return error if no middleware exists for scope, origin, and tabId and request is "eth_unsubscribe"', () => { const multichainMiddlewareManager = new MultichainMiddlewareManager(); const middleware = multichainMiddlewareManager.generateMultichainMiddlewareForOriginAndTabId( @@ -333,14 +333,14 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, ); expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).not.toHaveBeenCalled(); - expect(endSpy).toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); }); it('should remove middleware by origin and tabId', () => { @@ -365,13 +365,13 @@ describe('MultichainMiddlewareManager', () => { const endSpy = jest.fn(); middleware( - { jsonrpc: '2.0' as const, id: 0, method: 'eth_subscribe', scope }, + { jsonrpc: '2.0' as const, id: 0, method: 'method', scope }, { jsonrpc: '2.0', id: 0 }, nextSpy, endSpy, ); expect(middlewareSpy).not.toHaveBeenCalled(); - expect(nextSpy).not.toHaveBeenCalled(); - expect(endSpy).toHaveBeenCalled(); + expect(nextSpy).toHaveBeenCalled(); + expect(endSpy).not.toHaveBeenCalled(); }); }); From ee79d3ebe99bf1968b120d9ecccb8bbcb170e3b0 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 21 Jan 2025 12:46:24 -0800 Subject: [PATCH 146/146] eslint thresholds --- eslint-warning-thresholds.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eslint-warning-thresholds.json b/eslint-warning-thresholds.json index e83066be18d..3f81e2a510e 100644 --- a/eslint-warning-thresholds.json +++ b/eslint-warning-thresholds.json @@ -17,10 +17,10 @@ "jsdoc/check-tag-names": 375, "jsdoc/require-returns": 25, "jsdoc/tag-lines": 335, - "n/no-unsupported-features/node-builtins": 18, + "n/no-unsupported-features/node-builtins": 14, "n/prefer-global/text-encoder": 4, "n/prefer-global/text-decoder": 4, - "prettier/prettier": 115, + "prettier/prettier": 116, "promise/always-return": 3, "promise/catch-or-return": 2, "promise/param-names": 8,