From a07b83acd447fc9806ff142ce72106a98e722ecf Mon Sep 17 00:00:00 2001 From: Richard Meissner Date: Fri, 14 Jul 2023 15:00:34 +0200 Subject: [PATCH] Add simple list of plugins (#16) * Add simple list of plugins * Fix router * Add License; Rename meta data to metadata * Catch errors when loading plugins * Fix tests --- contracts/.gitignore | 2 +- contracts/contracts/Plugins.sol | 55 +-- contracts/src/tasks/test_registry.ts | 6 +- contracts/src/utils/metadata.ts | 36 +- contracts/test/SamplePlugin.spec.ts | 6 +- web/LICENSE | 165 ++++++++ web/package.json | 8 + web/src/App.tsx | 26 -- web/src/index.tsx | 20 +- web/src/logic/metadata.ts | 56 +++ web/src/logic/plugins.ts | 19 + web/src/logic/protocol.ts | 41 ++ web/src/logic/web3.ts | 5 + web/src/logo.svg | 14 +- web/src/{App.css => routes/home/Home.css} | 5 +- .../home/Home.test.tsx} | 6 +- web/src/routes/home/Home.tsx | 19 + web/src/routes/plugins/Plugin.tsx | 46 +++ web/src/routes/plugins/PluginList.tsx | 40 ++ web/src/routes/plugins/Plugins.css | 54 +++ web/yarn.lock | 358 +++++++++++++++++- 21 files changed, 895 insertions(+), 92 deletions(-) create mode 100644 web/LICENSE delete mode 100644 web/src/App.tsx create mode 100644 web/src/logic/metadata.ts create mode 100644 web/src/logic/plugins.ts create mode 100644 web/src/logic/protocol.ts create mode 100644 web/src/logic/web3.ts rename web/src/{App.css => routes/home/Home.css} (91%) rename web/src/{App.test.tsx => routes/home/Home.test.tsx} (60%) create mode 100644 web/src/routes/home/Home.tsx create mode 100644 web/src/routes/plugins/Plugin.tsx create mode 100644 web/src/routes/plugins/PluginList.tsx create mode 100644 web/src/routes/plugins/Plugins.css diff --git a/contracts/.gitignore b/contracts/.gitignore index 6608dbb..603b1e8 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -1,5 +1,5 @@ node_modules -build +build/ .env coverage coverage.json diff --git a/contracts/contracts/Plugins.sol b/contracts/contracts/Plugins.sol index 66442a3..4d90566 100644 --- a/contracts/contracts/Plugins.sol +++ b/contracts/contracts/Plugins.sol @@ -6,18 +6,18 @@ import {ISafeProtocolPlugin} from "@safe-global/safe-core-protocol/contracts/int import {ISafeProtocolManager} from "@safe-global/safe-core-protocol/contracts/interfaces/Manager.sol"; import {SafeTransaction, SafeRootAccess} from "@safe-global/safe-core-protocol/contracts/DataTypes.sol"; -enum MetaDataProviderType { +enum MetadataProviderType { IPFS, URL, Contract, Event } -interface MetaDataProvider { - function retrieveMetaData(bytes32 metaDataHash) external view returns (bytes memory metaData); +interface MetadataProvider { + function retrieveMetadata(bytes32 metadataHash) external view returns (bytes memory metadata); } -struct PluginMetaData { +struct PluginMetadata { string name; string version; bool requiresRootAccess; @@ -25,52 +25,57 @@ struct PluginMetaData { string appUrl; } -library PluginMetaDataOps { - function encode(PluginMetaData memory data) internal pure returns (bytes memory) { +library PluginMetadataOps { + function encode(PluginMetadata memory data) internal pure returns (bytes memory) { return abi.encodePacked( uint8(0x00), // Format uint8(0x00), // Format version - abi.encode(data.name, data.version, data.requiresRootAccess, data.iconUrl, data.appUrl) // Meta Data + abi.encode(data.name, data.version, data.requiresRootAccess, data.iconUrl, data.appUrl) // Plugin Metadata ); } - function decode(bytes calldata data) internal pure returns (PluginMetaData memory) { + function decode(bytes calldata data) internal pure returns (PluginMetadata memory) { require(bytes16(data[0:2]) == bytes16(0x0000), "Unsupported format or format version"); (string memory name, string memory version, bool requiresRootAccess, string memory iconUrl, string memory appUrl) = abi.decode( data[2:], (string, string, bool, string, string) ); - return PluginMetaData(name, version, requiresRootAccess, iconUrl, appUrl); + return PluginMetadata(name, version, requiresRootAccess, iconUrl, appUrl); } } -abstract contract BasePlugin is ISafeProtocolPlugin, MetaDataProvider { - using PluginMetaDataOps for PluginMetaData; +abstract contract BasePlugin is ISafeProtocolPlugin, MetadataProvider { + using PluginMetadataOps for PluginMetadata; string public name; string public version; bool public immutable requiresRootAccess; - bytes32 public immutable metaDataHash; - bytes private encodedMetaData; + bytes32 public immutable metadataHash; + bytes private encodedMetadata; - constructor(PluginMetaData memory metaData) { - name = metaData.name; - version = metaData.version; - requiresRootAccess = metaData.requiresRootAccess; - // MetaData Format + Format Version + Encoded MetaData - encodedMetaData = metaData.encode(); - metaDataHash = keccak256(encodedMetaData); + constructor(PluginMetadata memory metadata) { + name = metadata.name; + version = metadata.version; + requiresRootAccess = metadata.requiresRootAccess; + // Metadata Format + Format Version + Encoded Metadata + encodedMetadata = metadata.encode(); + metadataHash = keccak256(encodedMetadata); } + // TODO: Legacy version that should be removed function metaProvider() external view override returns (uint256 providerType, bytes memory location) { - providerType = uint256(MetaDataProviderType.Contract); + return metadataProvider(); + } + + function metadataProvider() public view returns (uint256 providerType, bytes memory location) { + providerType = uint256(MetadataProviderType.Contract); location = abi.encode(address(this)); } - function retrieveMetaData(bytes32 _metaDataHash) external view returns (bytes memory metaData) { - require(metaDataHash == _metaDataHash, "Cannot retrieve meta data"); - return encodedMetaData; + function retrieveMetadata(bytes32 _metadataHash) external view returns (bytes memory metadata) { + require(metadataHash == _metadataHash, "Cannot retrieve metadata"); + return encodedMetadata; } } @@ -79,7 +84,7 @@ contract SamplePlugin is BasePlugin { constructor( ISafeProtocolManager _manager - ) BasePlugin(PluginMetaData({name: "Sample Plugin", version: "1.0.0", requiresRootAccess: false, iconUrl: "", appUrl: ""})) { + ) BasePlugin(PluginMetadata({name: "Sample Plugin", version: "1.0.0", requiresRootAccess: false, iconUrl: "", appUrl: ""})) { manager = _manager; } diff --git a/contracts/src/tasks/test_registry.ts b/contracts/src/tasks/test_registry.ts index 02764b9..ad5ca27 100644 --- a/contracts/src/tasks/test_registry.ts +++ b/contracts/src/tasks/test_registry.ts @@ -3,7 +3,7 @@ import "@nomicfoundation/hardhat-ethers"; import { task } from "hardhat/config"; import { getPlugin, getRegistry, getSamplePlugin } from "../utils/contracts"; import { IntegrationType } from "../utils/constants"; -import { loadPluginMetaData } from "../utils/metadata"; +import { loadPluginMetadata } from "../utils/metadata"; task("register-plugin", "Registers the sample Plugin in the Safe{Core} test register") .setAction(async (_, hre) => { @@ -19,8 +19,8 @@ task("list-plugins", "List available Plugins in the Safe{Core} test register") const events = await registry.queryFilter(registry.filters.IntegrationAdded) for (const event of events) { const plugin = await getPlugin(hre, event.args.integration) - const metaData = await loadPluginMetaData(hre, plugin) - console.log(event.args.integration, metaData) + const metadata = await loadPluginMetadata(hre, plugin) + console.log(event.args.integration, metadata) } }); diff --git a/contracts/src/utils/metadata.ts b/contracts/src/utils/metadata.ts index a4aedb0..a3570d1 100644 --- a/contracts/src/utils/metadata.ts +++ b/contracts/src/utils/metadata.ts @@ -1,9 +1,9 @@ import { AbiCoder, isHexString, keccak256 } from "ethers"; -import { BasePlugin, MetaDataProvider } from "../../typechain-types"; +import { BasePlugin, MetadataProvider } from "../../typechain-types"; import { getInstance } from "../utils/contracts"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -interface PluginMetaData { +interface PluginMetadata { name: string; version: string; requiresRootAccess: boolean; @@ -16,36 +16,36 @@ interface PluginMetaData { const ProviderType_Contract = 2n; // const ProviderType_Event = 3n; -const PluginMetaDataType: string[] = ["string name", "string version", "bool requiresRootAccess", "string iconUrl", "string appUrl"]; +const PluginMetadataType: string[] = ["string name", "string version", "bool requiresRootAccess", "string iconUrl", "string appUrl"]; -const loadPluginMetaDataFromContract = async (hre: HardhatRuntimeEnvironment, provider: string, metaDataHash: string): Promise => { - const providerInstance = await getInstance(hre, "MetaDataProvider", provider); - return await providerInstance.retrieveMetaData(metaDataHash); +const loadPluginMetadataFromContract = async (hre: HardhatRuntimeEnvironment, provider: string, metadataHash: string): Promise => { + const providerInstance = await getInstance(hre, "MetadataProvider", provider); + return await providerInstance.retrieveMetadata(metadataHash); }; -const loadRawMetaData = async (hre: HardhatRuntimeEnvironment, plugin: BasePlugin, metaDataHash: string): Promise => { - const [type, source] = await plugin.metaProvider(); +const loadRawMetadata = async (hre: HardhatRuntimeEnvironment, plugin: BasePlugin, metadataHash: string): Promise => { + const [type, source] = await plugin.metadataProvider(); switch (type) { case ProviderType_Contract: - return loadPluginMetaDataFromContract(hre, AbiCoder.defaultAbiCoder().decode(["address"], source)[0], metaDataHash); + return loadPluginMetadataFromContract(hre, AbiCoder.defaultAbiCoder().decode(["address"], source)[0], metadataHash); default: - throw Error("Unsupported MetaDataProviderType"); + throw Error("Unsupported MetadataProviderType"); } }; -export const loadPluginMetaData = async (hre: HardhatRuntimeEnvironment, plugin: BasePlugin): Promise => { - const metaDataHash = await plugin.metaDataHash(); - const metaData = await loadRawMetaData(hre, plugin, metaDataHash); - if (metaDataHash !== keccak256(metaData)) throw Error("Invalid meta data retrieved!"); - return decodePluginMetaData(metaData); +export const loadPluginMetadata = async (hre: HardhatRuntimeEnvironment, plugin: BasePlugin): Promise => { + const metadataHash = await plugin.metadataHash(); + const metadata = await loadRawMetadata(hre, plugin, metadataHash); + if (metadataHash !== keccak256(metadata)) throw Error("Invalid metadata retrieved!"); + return decodePluginMetadata(metadata); }; -export const decodePluginMetaData = (data: string): PluginMetaData => { +export const decodePluginMetadata = (data: string): PluginMetadata => { if (!isHexString(data)) throw Error("Invalid data format"); const format = data.slice(2, 6); if (format !== "0000") throw Error("Unsupported format or format version"); - const metaData = data.slice(6); - const decoded = AbiCoder.defaultAbiCoder().decode(PluginMetaDataType, "0x" + metaData); + const metadata = data.slice(6); + const decoded = AbiCoder.defaultAbiCoder().decode(PluginMetadataType, "0x" + metadata); return { name: decoded[0], version: decoded[1], diff --git a/contracts/test/SamplePlugin.spec.ts b/contracts/test/SamplePlugin.spec.ts index 6f55ca3..08172be 100644 --- a/contracts/test/SamplePlugin.spec.ts +++ b/contracts/test/SamplePlugin.spec.ts @@ -2,7 +2,7 @@ import hre, { deployments } from "hardhat"; import { expect } from "chai"; import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { getSamplePlugin } from "../src/utils/contracts"; -import { loadPluginMetaData } from "../src/utils/metadata"; +import { loadPluginMetadata } from "../src/utils/metadata"; describe("SamplePlugin", async () => { let user1: SignerWithAddress; @@ -27,9 +27,9 @@ describe("SamplePlugin", async () => { expect(await plugin.requiresRootAccess()).to.be.false; }); - it("can retrieve meta data for module", async () => { + it("can retrieve metadata for module", async () => { const { plugin } = await setup(); - expect(await loadPluginMetaData(hre, plugin)).to.be.deep.eq({ + expect(await loadPluginMetadata(hre, plugin)).to.be.deep.eq({ name: "Sample Plugin", version: "1.0.0", requiresRootAccess: false, diff --git a/web/LICENSE b/web/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/web/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/web/package.json b/web/package.json index 828209c..18772d5 100644 --- a/web/package.json +++ b/web/package.json @@ -4,6 +4,11 @@ "homepage": ".", "private": true, "dependencies": { + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.14.0", + "@mui/material": "^5.14.0", + "@safe-global/safe-core-protocol": "^0.1.0-alpha.3", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", @@ -11,8 +16,11 @@ "@types/node": "^16.7.13", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "blockies-ts": "^1.0.0", + "ethers": "^6.6.3", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.14.1", "react-scripts": "5.0.1", "typescript": "^4.4.2", "web-vitals": "^2.1.0" diff --git a/web/src/App.tsx b/web/src/App.tsx deleted file mode 100644 index a53698a..0000000 --- a/web/src/App.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import logo from './logo.svg'; -import './App.css'; - -function App() { - return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
- ); -} - -export default App; diff --git a/web/src/index.tsx b/web/src/index.tsx index 032464f..9bd23fd 100644 --- a/web/src/index.tsx +++ b/web/src/index.tsx @@ -1,15 +1,31 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; -import App from './App'; +import Home from './routes/home/Home'; import reportWebVitals from './reportWebVitals'; +import { + createHashRouter, + RouterProvider, +} from "react-router-dom"; +import PluginList from './routes/plugins/PluginList'; + +const router = createHashRouter([ + { + path: "/", + element: , + }, + { + path: "/plugins", + element: , + }, +]); const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( - + ); diff --git a/web/src/logic/metadata.ts b/web/src/logic/metadata.ts new file mode 100644 index 0000000..2b9be45 --- /dev/null +++ b/web/src/logic/metadata.ts @@ -0,0 +1,56 @@ +import { AbiCoder, Contract, isHexString, keccak256 } from "ethers"; +import { getMetadataProvider } from "./protocol"; + +export interface PluginMetadata { + name: string; + version: string; + requiresRootAccess: boolean; + iconUrl: string; + appUrl: string; +} + +// const ProviderType_IPFS = BigInt(0); +// const ProviderType_URL = BigInt(1); +const ProviderType_Contract = BigInt(2); +// const ProviderType_Event = BigInt(3); + +const PluginMetadataType: string[] = ["string name", "string version", "bool requiresRootAccess", "string iconUrl", "string appUrl"]; + +const loadPluginMetadataFromContract = async (provider: string, metadataHash: string): Promise => { + const providerInstance = getMetadataProvider(provider); + return await providerInstance.retrieveMetadata(metadataHash); +}; + +const loadRawMetadata = async (plugin: Contract, metadataHash: string): Promise => { + const [type, source] = await plugin.metadataProvider(); + console.log(typeof type) + switch (type) { + case ProviderType_Contract: + return loadPluginMetadataFromContract(AbiCoder.defaultAbiCoder().decode(["address"], source)[0], metadataHash); + default: + throw Error("Unsupported MetadataProviderType"); + } +}; + +export const loadPluginMetadata = async (plugin: Contract): Promise => { + console.log({plugin}) + const metadataHash = await plugin.metadataHash(); + const metadata = await loadRawMetadata(plugin, metadataHash); + if (metadataHash !== keccak256(metadata)) throw Error("Invalid metadata retrieved!"); + return decodePluginMetadata(metadata); +}; + +export const decodePluginMetadata = (data: string): PluginMetadata => { + if (!isHexString(data)) throw Error("Invalid data format"); + const format = data.slice(2, 6); + if (format !== "0000") throw Error("Unsupported format or format version"); + const metadata = data.slice(6); + const decoded = AbiCoder.defaultAbiCoder().decode(PluginMetadataType, "0x" + metadata); + return { + name: decoded[0], + version: decoded[1], + requiresRootAccess: decoded[2], + iconUrl: decoded[3], + appUrl: decoded[4], + }; +}; diff --git a/web/src/logic/plugins.ts b/web/src/logic/plugins.ts new file mode 100644 index 0000000..626bfeb --- /dev/null +++ b/web/src/logic/plugins.ts @@ -0,0 +1,19 @@ +import { EventLog } from "ethers"; +import { PluginMetadata, loadPluginMetadata } from "./metadata"; +import { getPlugin, getRegistry } from "./protocol"; + +export const loadPluginDetails = async(pluginAddress: string): Promise => { + const plugin = getPlugin(pluginAddress) + const metadata = loadPluginMetadata(plugin) + return metadata +} + +export const loadPlugins = async(filterFlagged: boolean = true): Promise => { + const registry = getRegistry() + const addedEvents = (await registry.queryFilter(registry.filters.IntegrationAdded)) as EventLog[] + const addedIntegrations = addedEvents.map((event: EventLog) => event.args.integration) + if (!filterFlagged) return addedIntegrations; + const flaggedEvents = (await registry.queryFilter(registry.filters.IntegrationFlagged)) as EventLog[] + const flaggedIntegrations = flaggedEvents.map((event: EventLog) => event.args.integration) + return addedIntegrations.filter((integration) => flaggedIntegrations.indexOf(integration) < 0) +} \ No newline at end of file diff --git a/web/src/logic/protocol.ts b/web/src/logic/protocol.ts new file mode 100644 index 0000000..06b7f94 --- /dev/null +++ b/web/src/logic/protocol.ts @@ -0,0 +1,41 @@ +import { Interface, ethers } from "ethers" +import protocolDeployments from "@safe-global/safe-core-protocol" +import { getProvider } from "./web3" + +const Metadata_PROVIDER_ABI = [ + "function retrieveMetadata(bytes32 metadataHash) external view returns (bytes metadata)" +] + +const PLUGIN_ABI = [ + "function metadataHash() public view returns (bytes32 metadataHash)", + "function metadataProvider() external view returns (uint256 providerType, bytes location)" +] + +export const getRegistry = () => { + const provider = getProvider() + const registryInfo = protocolDeployments[5][0].contracts.TestSafeProtocolRegistryUnrestricted; + return new ethers.Contract( + registryInfo.address, + registryInfo.abi, + provider + ) +} + +export const getPlugin = (pluginAddress: string) => { + const provider = getProvider() + console.log(new Interface(PLUGIN_ABI)) + return new ethers.Contract( + pluginAddress, + PLUGIN_ABI, + provider + ) +} + +export const getMetadataProvider = (providerAddress: string) => { + const provider = getProvider() + return new ethers.Contract( + providerAddress, + Metadata_PROVIDER_ABI, + provider + ) +} \ No newline at end of file diff --git a/web/src/logic/web3.ts b/web/src/logic/web3.ts new file mode 100644 index 0000000..420e22d --- /dev/null +++ b/web/src/logic/web3.ts @@ -0,0 +1,5 @@ +import { AbstractProvider, ethers } from "ethers" + +export const getProvider = (): AbstractProvider => { + return new ethers.JsonRpcProvider("https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161") +} \ No newline at end of file diff --git a/web/src/logo.svg b/web/src/logo.svg index 9dfc1c0..6bf8e77 100644 --- a/web/src/logo.svg +++ b/web/src/logo.svg @@ -1 +1,13 @@ - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/web/src/App.css b/web/src/routes/home/Home.css similarity index 91% rename from web/src/App.css rename to web/src/routes/home/Home.css index 74b5e05..384d47b 100644 --- a/web/src/App.css +++ b/web/src/routes/home/Home.css @@ -24,8 +24,9 @@ color: white; } -.App-link { - color: #61dafb; +.App a { + color: #12ff80; + text-decoration: none; } @keyframes App-logo-spin { diff --git a/web/src/App.test.tsx b/web/src/routes/home/Home.test.tsx similarity index 60% rename from web/src/App.test.tsx rename to web/src/routes/home/Home.test.tsx index 2a68616..ad36e18 100644 --- a/web/src/App.test.tsx +++ b/web/src/routes/home/Home.test.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import App from './App'; +import Home from './Home'; test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); + render(); + const linkElement = screen.getByText(/Safe{Core} Protocol/i); expect(linkElement).toBeInTheDocument(); }); diff --git a/web/src/routes/home/Home.tsx b/web/src/routes/home/Home.tsx new file mode 100644 index 0000000..9477ea6 --- /dev/null +++ b/web/src/routes/home/Home.tsx @@ -0,0 +1,19 @@ +import { Link } from 'react-router-dom'; +import logo from '../../logo.svg'; +import './Home.css'; + +function Home() { + return ( +
+
+ logo +

+ Safe{Core} Protocol Demo +

+ Show availabe Plugins +
+
+ ); +} + +export default Home; diff --git a/web/src/routes/plugins/Plugin.tsx b/web/src/routes/plugins/Plugin.tsx new file mode 100644 index 0000000..c157076 --- /dev/null +++ b/web/src/routes/plugins/Plugin.tsx @@ -0,0 +1,46 @@ +import { FunctionComponent, useEffect, useState } from "react"; +import WarningIcon from '@mui/icons-material/Warning'; +import OpenInNewIcon from '@mui/icons-material/OpenInNew'; +import * as blockies from 'blockies-ts'; +import "./Plugins.css"; +import { PluginMetadata } from "../../logic/metadata"; +import { loadPluginDetails } from "../../logic/plugins"; + +type PluginMetaProps = { + metadata: PluginMetadata; + }; + +const PluginMeta: FunctionComponent = ({ metadata }) => { + return ( + <> + {metadata.name} - {metadata.version} + + ); +}; + +type PluginProps = { + address: string; +}; + +export const Plugin: FunctionComponent = ({ address }) => { + const [metadata, setMetadata] = useState(undefined); + const blocky = blockies.create({ seed: address }).toDataURL(); + useEffect(() => { + const fetchData = async() => { + try { + setMetadata(await loadPluginDetails(address)) + } catch(e) { + console.warn(e) + } + } + fetchData(); + }, [address]) + return ( +
+ +
{!metadata ? "Loading Metadata" : }
+ {metadata?.requiresRootAccess == true && } + {(metadata?.appUrl?.length ?? 0) > 0 && } +
+ ); +}; diff --git a/web/src/routes/plugins/PluginList.tsx b/web/src/routes/plugins/PluginList.tsx new file mode 100644 index 0000000..00d650c --- /dev/null +++ b/web/src/routes/plugins/PluginList.tsx @@ -0,0 +1,40 @@ +import { useEffect, useState } from 'react'; +import logo from '../../logo.svg'; +import './Plugins.css'; +import { loadPlugins } from '../../logic/plugins'; +import { Plugin } from './Plugin'; +import { Checkbox, FormControlLabel } from '@mui/material'; + +function PluginList() { + const [showFlagged, setFilterFlagged] = useState(false); + const [plugins, setPlugins] = useState([]); + useEffect(() => { + const fetchData = async() => { + try { + setPlugins([]) + setPlugins(await loadPlugins(!showFlagged)) + } catch(e) { + console.warn(e) + } + } + fetchData(); + }, [showFlagged]) + return ( +
+
+ logo +

+ Safe{Core} Protocol Demo +

+
+ setFilterFlagged(checked) } inputProps={{ 'aria-label': 'controlled' }} /> + } label="Show Flagged PlugIns" /> +
+ {plugins.map((plugin) => )} +
+
+ ); +} + +export default PluginList; diff --git a/web/src/routes/plugins/Plugins.css b/web/src/routes/plugins/Plugins.css new file mode 100644 index 0000000..75cee31 --- /dev/null +++ b/web/src/routes/plugins/Plugins.css @@ -0,0 +1,54 @@ +.Plugins { + height: 100vh; + width: 100vw; + text-align: center; + background-color: #282c34; + font-size: calc(10px + 2vmin); + color: white; + display: flex; + flex-direction: column; + align-items: center; + justify-content: start; +} + +.Plugin { + width: 100%; + text-align: start; + font-size: 20pt; + color: white; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +} + +.Plugin-title { + width: 100%; + text-align: start; +} + +.Plugins-header-logo { + height: 40pt; + pointer-events: none; +} + +.Plugins-header { + display: flex; + justify-content: center; + align-items: center; + flex-direction: row; +} + +.Plugins-list { + width: 600pt; + display: flex; + flex-direction: column; + align-items: start; + justify-content: start; + text-align: start; +} + +.AddressIcon { + border-radius: 50%; + margin-right: 10px; +} \ No newline at end of file diff --git a/web/yarn.lock b/web/yarn.lock index 87002cd..bce4ae5 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -12,6 +12,11 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855" integrity sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA== +"@adraffy/ens-normalize@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" + integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== + "@alloc/quick-lru@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" @@ -173,7 +178,7 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.22.5": +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== @@ -1123,7 +1128,7 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== @@ -1280,6 +1285,113 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== +"@emotion/babel-plugin@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" + integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/serialize" "^1.1.2" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.2.0" + +"@emotion/cache@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" + +"@emotion/hash@^0.9.1": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" + integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== + +"@emotion/is-prop-valid@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" + integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== + dependencies: + "@emotion/memoize" "^0.8.1" + +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== + +"@emotion/react@^11.11.1": + version "11.11.1" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.1.tgz#b2c36afac95b184f73b08da8c214fdf861fa4157" + integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.2" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.2.tgz#017a6e4c9b8a803bd576ff3d52a0ea6fa5a62b51" + integrity sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA== + dependencies: + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/unitless" "^0.8.1" + "@emotion/utils" "^1.2.1" + csstype "^3.0.2" + +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== + +"@emotion/styled@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346" + integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/is-prop-valid" "^1.2.1" + "@emotion/serialize" "^1.1.2" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + +"@emotion/unitless@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" + integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" + integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== + +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== + +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1633,6 +1745,99 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== +"@mui/base@5.0.0-beta.7": + version "5.0.0-beta.7" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.7.tgz#01cb99ac098af0ba989c7abc1474e3291c29414f" + integrity sha512-Pjbwm6gjiS96kOMF7E5fjEJsenc0tZBesrLQ4rrdi3eT/c/yhSWnPbCUkHSz8bnS0l3/VQ8bA+oERSGSV2PK6A== + dependencies: + "@babel/runtime" "^7.22.5" + "@emotion/is-prop-valid" "^1.2.1" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.7" + "@popperjs/core" "^2.11.8" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/core-downloads-tracker@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.0.tgz#ca394a1c53c215f4c6bf7f7460d8211298d7bbf6" + integrity sha512-SYBOVCatVDUf/lbrLGah09bHhX5WfUXg7kSskfLILr6SvKRni0NLp0aonxQ0SMALVVK3Qwa6cW4CdWuwS0gC1w== + +"@mui/icons-material@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.0.tgz#6452b00bc98dc407f20a927245e273113703166f" + integrity sha512-z7lYNteDi1GMkF9JP/m2RWuCYK1M/FlaeBSUK7/IhIYzIXNhAVjfD8jRq5vFBV31qkEi2aGBS2z5SfLXwH6U0A== + dependencies: + "@babel/runtime" "^7.22.5" + +"@mui/material@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.0.tgz#3d2afb4a3643774370cb5add873abcbbe8e7af27" + integrity sha512-HP7CP71NhMkui2HUIEKl2/JfuHMuoarSUWAKlNw6s17bl/Num9rN61EM6uUzc2A2zHjj/00A66GnvDnmixEJEw== + dependencies: + "@babel/runtime" "^7.22.5" + "@mui/base" "5.0.0-beta.7" + "@mui/core-downloads-tracker" "^5.14.0" + "@mui/system" "^5.14.0" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.7" + "@types/react-transition-group" "^4.4.6" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" + react-is "^18.2.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^5.13.7": + version "5.13.7" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.13.7.tgz#2f8ef5da066f3c6c6423bd4260d003a28d10b099" + integrity sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA== + dependencies: + "@babel/runtime" "^7.22.5" + "@mui/utils" "^5.13.7" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.13.2": + version "5.13.2" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.13.2.tgz#c87bd61c0ab8086d34828b6defe97c02bcd642ef" + integrity sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw== + dependencies: + "@babel/runtime" "^7.21.0" + "@emotion/cache" "^11.11.0" + csstype "^3.1.2" + prop-types "^15.8.1" + +"@mui/system@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.0.tgz#b7eeb799ae67d27b887fec4917ebd5e2be5a2faa" + integrity sha512-0HZGkX8miJbiNw+rjlZ9l0Cfkz1bSqfSHQH0EH9J+nx0aAm5cBleg9piOlLdCNIWGgecCqsw4x62erGrGjjcJg== + dependencies: + "@babel/runtime" "^7.22.5" + "@mui/private-theming" "^5.13.7" + "@mui/styled-engine" "^5.13.2" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.7" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" + +"@mui/types@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" + integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== + +"@mui/utils@^5.13.7": + version "5.13.7" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.13.7.tgz#7e6a8336e05eb2642667a5c02eb605351e27ec20" + integrity sha512-/3BLptG/q0u36eYED7Nhf4fKXmcKb6LjjT7ZMwhZIZSdSxVqDqSTmATW3a56n3KEPQUXCU9TpxAfCBQhs6brVA== + dependencies: + "@babel/runtime" "^7.22.5" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^18.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -1645,6 +1850,16 @@ resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== +"@noble/hashes@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" + integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== + +"@noble/secp256k1@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1681,6 +1896,16 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + +"@remix-run/router@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.1.tgz#fea7ac35ae4014637c130011f59428f618730498" + integrity sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ== + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -1723,6 +1948,11 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz#31b9c510d8cada9683549e1dbb4284cca5001faf" integrity sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw== +"@safe-global/safe-core-protocol@^0.1.0-alpha.3": + version "0.1.0-alpha.3" + resolved "https://registry.yarnpkg.com/@safe-global/safe-core-protocol/-/safe-core-protocol-0.1.0-alpha.3.tgz#355b81283b4ce611aa651af76186b1cd91ea0f45" + integrity sha512-iXIaqOrPuJVkTyLHlnzxa5+/oicK43snL6iH/m1f7nFqySvUlXcV29MeS9b3S5a6k8r3cMX9IlmK6GpWk0tx4w== + "@sinclair/typebox@^0.24.1": version "0.24.51" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" @@ -2113,6 +2343,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.1.tgz#a6033a8718653c50ac4962977e14d0f984d9527d" integrity sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^16.7.13": version "16.18.38" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.38.tgz#1dcdb6c54d02b323f621213745f2e44af30c73e6" @@ -2128,7 +2363,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/prop-types@*": +"@types/prop-types@*", "@types/prop-types@^15.7.5": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== @@ -2155,6 +2390,20 @@ dependencies: "@types/react" "*" +"@types/react-is@^18.2.1": + version "18.2.1" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-18.2.1.tgz#61d01c2a6fc089a53520c0b66996d458fdc46863" + integrity sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw== + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e" + integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^18.0.0": version "18.2.14" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.14.tgz#fa7a6fecf1ce35ca94e74874f70c56ce88f7a127" @@ -2541,6 +2790,11 @@ adjust-sourcemap-loader@^4.0.0: loader-utils "^2.0.0" regex-parser "^2.2.11" +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2980,6 +3234,11 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +blockies-ts@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/blockies-ts/-/blockies-ts-1.0.0.tgz#d51cda8d8a9df726fb900084e12f86912beb8591" + integrity sha512-mL9NO/FjYbFjaSDA5tw/qkUwEXrBG1bHSoPhAFG9CAzDaHTwQHzvYByAYUBmnqYciFsJvdxWKGtyOLgaSKoUkA== + bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3224,6 +3483,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clsx@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3366,7 +3630,7 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -3629,7 +3893,7 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2: +csstype@^3.0.2, csstype@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== @@ -3841,6 +4105,14 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" @@ -4389,6 +4661,19 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +ethers@^6.6.3: + version "6.6.3" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.6.3.tgz#9bf11d1bd0f18c7c55087d1a52fdc8f3c33c8bab" + integrity sha512-g8wLXeRWSGDD0T+wsL3pvyc3aYnmxEEAwH8LSoDTDRhRsmJeNs9YMXlNU7ax2caO+zHkeI9MkHiz6rwxEjN4Mw== + dependencies: + "@adraffy/ens-normalize" "1.9.2" + "@noble/hashes" "1.1.2" + "@noble/secp256k1" "1.7.1" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -4595,6 +4880,11 @@ find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -4991,6 +5281,13 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hoopy@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" @@ -7560,7 +7857,7 @@ prompts@^2.0.1, prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -7693,7 +7990,7 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -7703,7 +8000,7 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^18.0.0: +react-is@^18.0.0, react-is@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== @@ -7713,6 +8010,21 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== +react-router-dom@^6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.1.tgz#0ad7ba7abdf75baa61169d49f096f0494907a36f" + integrity sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw== + dependencies: + "@remix-run/router" "1.7.1" + react-router "6.14.1" + +react-router@6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.1.tgz#5e82bcdabf21add859dc04b1859f91066b3a5810" + integrity sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g== + dependencies: + "@remix-run/router" "1.7.1" + react-scripts@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" @@ -7768,6 +8080,16 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -8286,6 +8608,11 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + source-map@^0.7.3: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" @@ -8525,6 +8852,11 @@ stylehacks@^5.1.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + sucrase@^3.32.0: version "3.32.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7" @@ -8808,6 +9140,11 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -9469,6 +9806,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"