From 644f4d0c55cb10ece1a776a80a121ce8506faf95 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 12:35:41 -0700 Subject: [PATCH 1/5] 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 2/5] 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 9bcf86965d48a8499bdfe12d279e3dbc1edeb4f2 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Thu, 17 Oct 2024 13:18:08 -0700 Subject: [PATCH 3/5] 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 109a7bf5a25ef4f9b15a3ffe081cacac286d0114 Mon Sep 17 00:00:00 2001 From: jiexi Date: Thu, 17 Oct 2024 14:21:11 -0700 Subject: [PATCH 4/5] 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 738c29177e159f8465a587bd2de50ba069320c03 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 21 Oct 2024 13:13:23 -0500 Subject: [PATCH 5/5] fix up README graphs --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d13cf342474..91009bca927 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ 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; @@ -134,6 +135,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 +153,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;