From e66a12c88ae1164c5ba9d2dcc9d8bc102317ba54 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sun, 31 Oct 2021 11:26:33 +0800 Subject: [PATCH 01/41] chore: add flow chain chore: scaffolding chore: add flow plugin scaffolding refatcor: add EVM plugin scaffolding refactor: move Flow to a single pkg refactor: add web3-kit chore: account auth chore(ui): provider icon chore(ui): dashboard components chore(ui): account overview --- .i18n-codegen.json | 12 + packages/dashboard/package.json | 1 + packages/dashboard/tsconfig.json | 1 + packages/mask/.webpack/config.ts | 7 +- packages/mask/package.json | 1 + packages/mask/src/plugin-infra/register.ts | 2 + .../src/plugins/EVM/UI/Dashboard/index.tsx | 16 ++ .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 16 ++ .../plugins/EVM/UI/components/PluginIcon.tsx | 16 ++ .../plugins/EVM/UI/components/PluginPanel.tsx | 239 ++++++++++++++++++ .../plugins/EVM/UI/components/Provider.tsx | 62 +++++ packages/mask/src/plugins/EVM/Worker/index.ts | 9 + packages/mask/src/plugins/EVM/apis/index.ts | 1 + .../mask/src/plugins/EVM/assets/ethereum.png | Bin 0 -> 692 bytes packages/mask/src/plugins/EVM/base.ts | 15 ++ packages/mask/src/plugins/EVM/constants.ts | 5 + packages/mask/src/plugins/EVM/index.ts | 23 ++ packages/mask/src/plugins/EVM/messages.ts | 6 + packages/mask/src/plugins/EVM/services.ts | 1 + packages/mask/src/plugins/EVM/types.ts | 1 + .../src/plugins/Wallet/Dashboard/index.tsx | 2 +- .../index.tsx | 0 .../PluginProviderRender.tsx | 18 ++ .../SelectProviderDialog/ProviderTab.tsx | 43 ++++ .../SelectProviderDialog/ProviderTabPanel.tsx | 21 ++ .../SNSAdaptor/SelectProviderDialog/index.tsx | 232 +---------------- .../Wallet/SNSAdaptor/SelectWalletDialog.tsx | 3 +- .../src/plugins/Wallet/SNSAdaptor/index.tsx | 2 +- packages/mask/src/utils/flags.ts | 1 + packages/plugin-infra/src/types.ts | 14 +- packages/plugins/Flow/package.json | 17 ++ .../plugins/Flow/src/UI/Dashboard/index.tsx | 16 ++ .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 16 ++ .../src/UI/components/AccountOverview.tsx | 7 + .../Flow/src/UI/components/AssetList.tsx | 7 + .../Flow/src/UI/components/CollectionList.tsx | 7 + .../src/UI/components/DashboardAssetsTab.tsx | 7 + .../src/UI/components/DashboardHistoryTab.tsx | 7 + .../src/UI/components/DashboardOverview.tsx | 7 + .../UI/components/DashboardTransferTab.tsx | 7 + .../Flow/src/UI/components/NetworkIcon.tsx | 12 + .../Flow/src/UI/components/PluginIcon.tsx | 16 ++ .../Flow/src/UI/components/PluginPanel.tsx | 104 ++++++++ .../Flow/src/UI/components/ProviderIcon.tsx | 11 + .../src/UI/components/TransactionList.tsx | 7 + packages/plugins/Flow/src/Worker/index.ts | 9 + packages/plugins/Flow/src/apis/index.ts | 1 + packages/plugins/Flow/src/assets/flow.png | Bin 0 -> 5078 bytes packages/plugins/Flow/src/base.ts | 17 ++ packages/plugins/Flow/src/constants.ts | 5 + packages/plugins/Flow/src/helpers/index.ts | 1 + packages/plugins/Flow/src/hooks/index.ts | 1 + packages/plugins/Flow/src/index.ts | 23 ++ packages/plugins/Flow/src/locales/en-US.json | 6 + packages/plugins/Flow/src/locales/index.ts | 12 + packages/plugins/Flow/src/locales/zh-TW.json | 6 + packages/plugins/Flow/src/messages.ts | 7 + packages/plugins/Flow/src/services.ts | 1 + packages/plugins/Flow/src/types.ts | 1 + packages/plugins/Flow/tsconfig.json | 17 ++ packages/plugins/tsconfig.json | 2 +- packages/web3-constants/compile-constants.ts | 2 + packages/web3-constants/flow/auth.json | 14 + packages/web3-kit/package.json | 6 + packages/web3-kit/src/helpers/constants.ts | 68 +++++ packages/web3-kit/src/helpers/index.ts | 2 + packages/web3-kit/src/helpers/lookupTable.ts | 7 + packages/web3-kit/src/index.ts | 1 + packages/web3-kit/src/types.ts | 2 + packages/web3-kit/tsconfig.json | 9 + packages/web3-shared/flow/constants/index.ts | 6 + packages/web3-shared/flow/env.d.ts | 27 ++ packages/web3-shared/flow/hooks/index.ts | 7 + packages/web3-shared/flow/hooks/useAccount.ts | 13 + packages/web3-shared/flow/hooks/useBalance.ts | 9 + .../web3-shared/flow/hooks/useChainConfig.ts | 14 + packages/web3-shared/flow/hooks/useChainId.ts | 5 + .../web3-shared/flow/hooks/useCurrentUser.ts | 12 + packages/web3-shared/flow/hooks/useFCL.ts | 19 ++ packages/web3-shared/flow/hooks/useScript.ts | 10 + packages/web3-shared/flow/index.ts | 3 + packages/web3-shared/flow/package.json | 13 + packages/web3-shared/flow/pipes/index.ts | 37 +++ packages/web3-shared/flow/tsconfig.json | 9 + packages/web3-shared/flow/types.ts | 10 + packages/web3-shared/tsconfig.json | 2 +- pnpm-lock.yaml | 158 +++++++++++- pnpm-workspace.yaml | 3 + 88 files changed, 1365 insertions(+), 230 deletions(-) create mode 100644 packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/components/Provider.tsx create mode 100644 packages/mask/src/plugins/EVM/Worker/index.ts create mode 100644 packages/mask/src/plugins/EVM/apis/index.ts create mode 100644 packages/mask/src/plugins/EVM/assets/ethereum.png create mode 100644 packages/mask/src/plugins/EVM/base.ts create mode 100644 packages/mask/src/plugins/EVM/constants.ts create mode 100644 packages/mask/src/plugins/EVM/index.ts create mode 100644 packages/mask/src/plugins/EVM/messages.ts create mode 100644 packages/mask/src/plugins/EVM/services.ts create mode 100644 packages/mask/src/plugins/EVM/types.ts rename packages/mask/src/plugins/Wallet/SNSAdaptor/{RRC20TokenListDialog => ERC20TokenListDialog}/index.tsx (100%) create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx create mode 100644 packages/plugins/Flow/package.json create mode 100644 packages/plugins/Flow/src/UI/Dashboard/index.tsx create mode 100644 packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx create mode 100644 packages/plugins/Flow/src/UI/components/AccountOverview.tsx create mode 100644 packages/plugins/Flow/src/UI/components/AssetList.tsx create mode 100644 packages/plugins/Flow/src/UI/components/CollectionList.tsx create mode 100644 packages/plugins/Flow/src/UI/components/DashboardAssetsTab.tsx create mode 100644 packages/plugins/Flow/src/UI/components/DashboardHistoryTab.tsx create mode 100644 packages/plugins/Flow/src/UI/components/DashboardOverview.tsx create mode 100644 packages/plugins/Flow/src/UI/components/DashboardTransferTab.tsx create mode 100644 packages/plugins/Flow/src/UI/components/NetworkIcon.tsx create mode 100644 packages/plugins/Flow/src/UI/components/PluginIcon.tsx create mode 100644 packages/plugins/Flow/src/UI/components/PluginPanel.tsx create mode 100644 packages/plugins/Flow/src/UI/components/ProviderIcon.tsx create mode 100644 packages/plugins/Flow/src/UI/components/TransactionList.tsx create mode 100644 packages/plugins/Flow/src/Worker/index.ts create mode 100644 packages/plugins/Flow/src/apis/index.ts create mode 100644 packages/plugins/Flow/src/assets/flow.png create mode 100644 packages/plugins/Flow/src/base.ts create mode 100644 packages/plugins/Flow/src/constants.ts create mode 100644 packages/plugins/Flow/src/helpers/index.ts create mode 100644 packages/plugins/Flow/src/hooks/index.ts create mode 100644 packages/plugins/Flow/src/index.ts create mode 100644 packages/plugins/Flow/src/locales/en-US.json create mode 100644 packages/plugins/Flow/src/locales/index.ts create mode 100644 packages/plugins/Flow/src/locales/zh-TW.json create mode 100644 packages/plugins/Flow/src/messages.ts create mode 100644 packages/plugins/Flow/src/services.ts create mode 100644 packages/plugins/Flow/src/types.ts create mode 100644 packages/plugins/Flow/tsconfig.json create mode 100644 packages/web3-constants/flow/auth.json create mode 100644 packages/web3-kit/package.json create mode 100644 packages/web3-kit/src/helpers/constants.ts create mode 100644 packages/web3-kit/src/helpers/index.ts create mode 100644 packages/web3-kit/src/helpers/lookupTable.ts create mode 100644 packages/web3-kit/src/index.ts create mode 100644 packages/web3-kit/src/types.ts create mode 100644 packages/web3-kit/tsconfig.json create mode 100644 packages/web3-shared/flow/constants/index.ts create mode 100644 packages/web3-shared/flow/env.d.ts create mode 100644 packages/web3-shared/flow/hooks/index.ts create mode 100644 packages/web3-shared/flow/hooks/useAccount.ts create mode 100644 packages/web3-shared/flow/hooks/useBalance.ts create mode 100644 packages/web3-shared/flow/hooks/useChainConfig.ts create mode 100644 packages/web3-shared/flow/hooks/useChainId.ts create mode 100644 packages/web3-shared/flow/hooks/useCurrentUser.ts create mode 100644 packages/web3-shared/flow/hooks/useFCL.ts create mode 100644 packages/web3-shared/flow/hooks/useScript.ts create mode 100644 packages/web3-shared/flow/index.ts create mode 100644 packages/web3-shared/flow/package.json create mode 100644 packages/web3-shared/flow/pipes/index.ts create mode 100644 packages/web3-shared/flow/tsconfig.json create mode 100644 packages/web3-shared/flow/types.ts diff --git a/.i18n-codegen.json b/.i18n-codegen.json index 913ce163e46a..59bea5dd2082 100644 --- a/.i18n-codegen.json +++ b/.i18n-codegen.json @@ -73,6 +73,18 @@ "trans": "Translate", "sourceMap": "inline" } + }, + { + "input": "./packages/plugins/Flow/src/locales/en-US.json", + "output": "./packages/plugins/Flow/src/locales/i18n_generated", + "parser": "i18next", + "generator": { + "type": "i18next/react-hooks", + "hooks": "useI18N", + "namespace": "com.maskbook.flow", + "trans": "Translate", + "sourceMap": "inline" + } } ] } diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index a5cf9cce1895..06c873a0742a 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -17,6 +17,7 @@ "@masknet/plugin-example": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/plugin-wallet": "workspace:*", + "@masknet/plugin-flow": "workspace:*", "@masknet/public-api": "workspace:*", "@masknet/shared": "workspace:*", "@masknet/storybook-shared": "workspace:*", diff --git a/packages/dashboard/tsconfig.json b/packages/dashboard/tsconfig.json index 1f60a905f93b..892aa214ca71 100644 --- a/packages/dashboard/tsconfig.json +++ b/packages/dashboard/tsconfig.json @@ -14,6 +14,7 @@ { "path": "../icons/" }, { "path": "../plugin-infra" }, { "path": "../plugins/Wallet/" }, + { "path": "../plugins/Flow/" }, { "path": "../backup-format/" } ] } diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index ea683909e202..60acb91dbdb8 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -71,12 +71,15 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { '@masknet/shared-base': join(__dirname, '../../shared-base/src/'), '@masknet/theme': join(__dirname, '../../theme/src/'), '@masknet/icons': join(__dirname, '../../icons/index.ts'), + '@masknet/web3-kit': join(__dirname, '../../web3-kit/src/'), + '@masknet/web3-shared-evm': join(__dirname, '../../web3-shared/evm/'), + '@masknet/web3-shared-flow': join(__dirname, '../../web3-shared/flow/'), + '@masknet/web3-shared-solana': join(__dirname, '../../web3-shared/solana/'), '@masknet/plugin-infra': join(__dirname, '../../plugin-infra/src/'), '@masknet/plugin-example': join(__dirname, '../../plugins/example/src/'), + '@masknet/plugin-flow': join(__dirname, '../../plugins/Flow/src/'), '@masknet/plugin-wallet': join(__dirname, '../../plugins/Wallet/src/'), '@masknet/external-plugin-previewer': join(__dirname, '../../external-plugin-previewer/src/'), - '@masknet/web3-shared-evm': join(__dirname, '../../web3-shared/evm/'), - '@masknet/web3-shared-solana': join(__dirname, '../../web3-shared/solana/'), '@masknet/public-api': join(__dirname, '../../public-api/src/'), '@masknet/sdk': join(__dirname, '../../mask-sdk/server/'), '@masknet/backup-format': join(__dirname, '../../backup-format/src/'), diff --git a/packages/mask/package.json b/packages/mask/package.json index b0417d4655f9..a67cfe382842 100644 --- a/packages/mask/package.json +++ b/packages/mask/package.json @@ -24,6 +24,7 @@ "@masknet/plugin-example": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/plugin-wallet": "workspace:*", + "@masknet/plugin-flow": "workspace:*", "@masknet/public-api": "workspace:*", "@masknet/sdk": "workspace:*", "@masknet/shared": "workspace:*", diff --git a/packages/mask/src/plugin-infra/register.ts b/packages/mask/src/plugin-infra/register.ts index 7449539d3293..51d1fdef6751 100644 --- a/packages/mask/src/plugin-infra/register.ts +++ b/packages/mask/src/plugin-infra/register.ts @@ -2,6 +2,7 @@ // packages/dashboard/src/initialization/plugins.ts import '@masknet/plugin-example' +import '@masknet/plugin-flow' import '../plugins/Wallet' import '../plugins/RedPacket' import '../plugins/ITO' @@ -23,5 +24,6 @@ import '../plugins/Furucombo' import '../plugins/MaskBox' import '../plugins/Profile' import '../plugins/Pets' +import '../plugins/EVM' // import '../plugins/NFT' // import '../plugins/Airdrop' diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx new file mode 100644 index 000000000000..48bada595505 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -0,0 +1,16 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../../base' +import { PluginIcon } from '../components/PluginIcon' +import { PluginPanel } from '../components/PluginPanel' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal) {}, + SelectProviderDialogEntry: { + name: 'EVM', + icon: , + panel: , + }, +} + +export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx new file mode 100644 index 000000000000..48bada595505 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -0,0 +1,16 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../../base' +import { PluginIcon } from '../components/PluginIcon' +import { PluginPanel } from '../components/PluginPanel' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal) {}, + SelectProviderDialogEntry: { + name: 'EVM', + icon: , + panel: , + }, +} + +export default sns diff --git a/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx b/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx new file mode 100644 index 000000000000..900f3cdc3935 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx @@ -0,0 +1,16 @@ +import { makeStyles } from '@masknet/theme' + +const useStyles = makeStyles()({ + image: { + width: 24, + height: 24, + }, +}) + +export interface PluginIconProps {} + +export function PluginIcon(props: PluginIconProps) { + const { classes } = useStyles() + const iconURL = new URL('../../assets/ethereum.png', import.meta.url).toString() + return +} diff --git a/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx b/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx new file mode 100644 index 000000000000..5680b79afcba --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx @@ -0,0 +1,239 @@ +import { useCallback, useEffect, useState } from 'react' +import { useAsync } from 'react-use' +import { getMaskColor, makeStyles } from '@masknet/theme' +import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' +import { getChainIdFromNetworkType, ProviderType, useAccount, useChainId, useWallets } from '@masknet/web3-shared-evm' +import { useValueRef, useRemoteControlledDialog, useStylesExtends, NetworkIcon } from '@masknet/shared' +import { unreachable } from '@dimensiondev/kit' +import { SuccessIcon } from '@masknet/icons' +import { PopupRoutes } from '@masknet/shared-base' +import { WalletMessages } from '@masknet/plugin-wallet' +import { useHistory } from 'react-router-dom' +import classnames from 'classnames' +import { Flags, useI18N } from '../../../../utils' +import Services from '../../../../extension/service' +import { currentNetworkSettings, currentProviderSettings } from '../../../Wallet/settings' +import { WalletRPC } from '../../../Wallet/messages' +import { MaskIcon } from '../../../../resources/MaskIcon' +import { MetaMaskIcon } from '../../../../resources/MetaMaskIcon' +import { WalletConnectIcon } from '../../../../resources/WalletConnectIcon' +import { Provider } from './Provider' + +const useStyles = makeStyles()((theme) => ({ + paper: { + width: '750px !important', + maxWidth: 'unset', + }, + content: { + padding: theme.spacing(0), + }, + step: { + flexGrow: 1, + marginTop: 21, + '&:first-child': { + marginTop: 0, + }, + }, + stepTitle: { + fontSize: 19, + fontWeight: 'bold', + }, + stepContent: { + marginTop: 21, + }, + networkDisabled: { + opacity: 0.5, + }, + networkList: { + display: 'flex', + gap: 32, + }, + networkItem: { + width: 'auto', + padding: 0, + }, + iconWrapper: { + position: 'relative', + cursor: 'pointer', + height: 48, + width: 48, + borderRadius: 48, + backgroundColor: getMaskColor(theme).twitterBackground, + }, + networkIcon: { + backgroundColor: getMaskColor(theme).twitterBackground, + }, + checkedBadge: { + position: 'absolute', + right: 0, + bottom: 0, + width: 14, + height: 14, + background: '#fff', + borderRadius: '50%', + }, + alert: { + fontSize: 12, + display: 'flex', + alignItems: 'center', + marginTop: theme.spacing(1), + }, + grid: { + width: '100%', + margin: theme.spacing(2, 0, 0), + }, + providerIcon: { + fontSize: 45, + }, + tip: { + fontSize: 12, + }, +})) + +export interface PluginPanelProps {} + +export function PluginPanel(props: PluginPanelProps) { + const { t } = useI18N() + const classes = useStylesExtends(useStyles(), props) + + const account = useAccount() + const chainId = useChainId() + const history = useHistory() + + //#region remote controlled dialog logic + const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) + //#endregion + + //#region wallet status dialog + const { openDialog: openWalletStatusDialog } = useRemoteControlledDialog( + WalletMessages.events.walletStatusDialogUpdated, + ) + //#endregion + + //#region select wallet dialog + const { setDialog: setSelectWalletDialog } = useRemoteControlledDialog( + WalletMessages.events.selectWalletDialogUpdated, + ) + //#endregion + + //#region connect wallet dialog + const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( + WalletMessages.events.connectWalletDialogUpdated, + ) + //#endregion + + //#region wallet connect QR code dialog + const { setDialog: setWalletConnectDialog } = useRemoteControlledDialog( + WalletMessages.events.walletConnectQRCodeDialogUpdated, + ) + //#endregion + + const wallets = useWallets(ProviderType.MaskWallet) + const selectedNetworkType = useValueRef(currentNetworkSettings) + const selectedProviderType = useValueRef(currentProviderSettings) + + //#region undetermined network type + const [undeterminedNetworkType, setUndeterminedNetworkType] = useState(selectedNetworkType) + useEffect(() => { + if (!open) return + setUndeterminedNetworkType(selectedNetworkType) + }, [open]) + //#endregion + + const { value: networks } = useAsync(async () => WalletRPC.getSupportedNetworks(), []) + + const onConnectProvider = useCallback( + async (providerType: ProviderType) => { + closeDialog() + + switch (providerType) { + case ProviderType.MaskWallet: + await Services.Helper.openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { + chainId: getChainIdFromNetworkType(undeterminedNetworkType), + }) + break + case ProviderType.MetaMask: + case ProviderType.WalletConnect: + setConnectWalletDialog({ + open: true, + providerType, + networkType: undeterminedNetworkType, + }) + break + case ProviderType.CustomNetwork: + throw new Error('To be implemented.') + default: + unreachable(providerType) + } + }, + [ + account, + chainId, + wallets, + history, + closeDialog, + undeterminedNetworkType, + selectedProviderType, + openWalletStatusDialog, + setSelectWalletDialog, + setWalletConnectDialog, + ], + ) + + return ( + <> + + + 1. Choose Network + + + {networks?.map((network) => ( + { + setUndeterminedNetworkType(network) + }}> +
+ + {undeterminedNetworkType === network && ( + + )} +
+
+ ))} +
+
+ + + 2. Choose Wallet + + + + } + name="Mask Network" + onClick={() => onConnectProvider(ProviderType.MaskWallet)} + /> + + {Flags.metamask_support_enabled ? ( + + } + name="MetaMask" + onClick={() => onConnectProvider(ProviderType.MetaMask)} + /> + + ) : null} + + } + name="WalletConnect" + onClick={() => onConnectProvider(ProviderType.WalletConnect)} + /> + + + + + ) +} diff --git a/packages/mask/src/plugins/EVM/UI/components/Provider.tsx b/packages/mask/src/plugins/EVM/UI/components/Provider.tsx new file mode 100644 index 000000000000..e24dfc7cfc36 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/components/Provider.tsx @@ -0,0 +1,62 @@ +import { Typography, Card, ButtonBase, ButtonBaseProps } from '@mui/material' +import { makeStyles } from '@masknet/theme' +import { useStylesExtends } from '@masknet/shared' +import { getMaskColor } from '@masknet/theme' + +const useStyles = makeStyles()((theme) => ({ + root: { + textAlign: 'center', + }, + content: { + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: theme.spacing(4, 1), + backgroundColor: getMaskColor(theme).twitterBackground, + }, + logo: { + width: 45, + height: 45, + marginBottom: theme.spacing(2), + }, + name: { + fontSize: 16, + fontWeight: 'normal', + whiteSpace: 'nowrap', + marginBottom: theme.spacing(1), + }, + description: { + fontSize: 14, + fontWeight: 300, + }, +})) + +export interface ProviderProps + extends withClasses { + logo: React.ReactNode + name: React.ReactNode + description?: React.ReactNode + onClick?: () => void + ButtonBaseProps?: Partial +} + +export function Provider(props: ProviderProps) { + const classes = useStylesExtends(useStyles(), props) + return ( + + +
{props.logo}
+ + {props.name} + + {props.description && ( + + {props.description} + + )} +
+
+ ) +} diff --git a/packages/mask/src/plugins/EVM/Worker/index.ts b/packages/mask/src/plugins/EVM/Worker/index.ts new file mode 100644 index 000000000000..824d930b57e1 --- /dev/null +++ b/packages/mask/src/plugins/EVM/Worker/index.ts @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' +import '../messages' + +const worker: Plugin.Worker.Definition = { + ...base, + init(signal) {}, +} +export default worker diff --git a/packages/mask/src/plugins/EVM/apis/index.ts b/packages/mask/src/plugins/EVM/apis/index.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/mask/src/plugins/EVM/apis/index.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/mask/src/plugins/EVM/assets/ethereum.png b/packages/mask/src/plugins/EVM/assets/ethereum.png new file mode 100644 index 0000000000000000000000000000000000000000..44ff0159cfe4ddbad1671c32d92117d56b3ab968 GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!|1AIbUfwV_NhDSsikPHYY@Q6qU zqg0OwAWHL$OmhzhN&y)_E>H^0jm-3jNb!hF3rI-tib{142ck5us4RD&;>a|&Fpw_K z@O00}6wmNfuc&m-aF8ybplehrkOUf{U9e6SXt7#JkY6x^!hHvU`TG<0H@q*Xe}8|$ z`*??Vf&2;Q4c7Mute;RYA-}&rz~Fqv=Z!iH42&l{T^vIy;@)1rnfKU$hczH*Q%Ys$ z>2`(D~Sb7WcP6ts+g#i~`SwB$UeH>>*U7O1-BFz~Em zWVG0n@t90CDj@KS8{=ogIhZtw4pH#Gp+?Ba~mZRQ+x&lR%tyX~l;aQ@?u!nf?7CkJ<4`g&7B{{6Lm4~`v` zPY=GqBfeX7S4E1C&nnp!0jJc`WhV2yo_KPS*4FcB(?e!{Yxr*vo5@}yi)3PA@oy>dnWlF{mEOZh`>RKH@6TB=xydly@RQYfR(svpXXp+IoeUi)gJD$AUke!x_~ N;OXk;vd$@?2>`2$Ba;9C literal 0 HcmV?d00001 diff --git a/packages/mask/src/plugins/EVM/base.ts b/packages/mask/src/plugins/EVM/base.ts new file mode 100644 index 000000000000..07d100412494 --- /dev/null +++ b/packages/mask/src/plugins/EVM/base.ts @@ -0,0 +1,15 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION } from './constants' + +export const base: Plugin.Shared.Definition = { + ID: PLUGIN_ID, + icon: PLUGIN_ICON, + name: { fallback: PLUGIN_NAME }, + description: { fallback: PLUGIN_DESCRIPTION }, + publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, + enableRequirement: { + architecture: { app: true, web: true }, + networks: { type: 'opt-out', networks: {} }, + target: 'stable', + }, +} diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts new file mode 100644 index 000000000000..a462fe41914d --- /dev/null +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -0,0 +1,5 @@ +export const PLUGIN_META_KEY = 'com.maskbook.evm' +export const PLUGIN_ID = 'com.maskbook.evm' +export const PLUGIN_NAME = 'EVM' +export const PLUGIN_ICON = 'Ξ' +export const PLUGIN_DESCRIPTION = '' diff --git a/packages/mask/src/plugins/EVM/index.ts b/packages/mask/src/plugins/EVM/index.ts new file mode 100644 index 000000000000..48ab76cba202 --- /dev/null +++ b/packages/mask/src/plugins/EVM/index.ts @@ -0,0 +1,23 @@ +import { registerPlugin } from '@masknet/plugin-infra' +import { base } from './base' + +registerPlugin({ + ...base, + SNSAdaptor: { + load: () => import('./UI/SNSAdaptor'), + hotModuleReload: (hot) => + import.meta.webpackHot && + import.meta.webpackHot.accept('./UI/SNSAdaptor', () => hot(import('./UI/SNSAdaptor'))), + }, + Dashboard: { + load: () => import('./UI/Dashboard'), + hotModuleReload: (hot) => + import.meta.webpackHot && + import.meta.webpackHot.accept('./UI/Dashboard', () => hot(import('./UI/Dashboard'))), + }, + Worker: { + load: () => import('./Worker'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Worker', () => hot(import('./Worker'))), + }, +}) diff --git a/packages/mask/src/plugins/EVM/messages.ts b/packages/mask/src/plugins/EVM/messages.ts new file mode 100644 index 000000000000..b57cc246556d --- /dev/null +++ b/packages/mask/src/plugins/EVM/messages.ts @@ -0,0 +1,6 @@ +import { createPluginMessage, createPluginRPC } from '@masknet/plugin-infra' +import { PLUGIN_ID } from './constants' + +if (import.meta.webpackHot) import.meta.webpackHot.accept() +const EVM_Message = createPluginMessage(PLUGIN_ID) +export const EVM_RPC = createPluginRPC(PLUGIN_ID, () => import('./services'), EVM_Message.rpc) diff --git a/packages/mask/src/plugins/EVM/services.ts b/packages/mask/src/plugins/EVM/services.ts new file mode 100644 index 000000000000..5914b704d67f --- /dev/null +++ b/packages/mask/src/plugins/EVM/services.ts @@ -0,0 +1 @@ +export * from './apis' diff --git a/packages/mask/src/plugins/EVM/types.ts b/packages/mask/src/plugins/EVM/types.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/mask/src/plugins/EVM/types.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx index ace3209cb356..a4ed6d5c5208 100644 --- a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx +++ b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx @@ -12,7 +12,7 @@ import { ConnectWalletDialog } from '../SNSAdaptor/ConnectWalletDialog' import { useStartWatchChainState } from '../hooks/useStartWatchChainState' import { WalletRiskWarningDialog } from '../SNSAdaptor/RiskWarningDialog' import { GasSettingDialog } from '../SNSAdaptor/GasSettingDialog' -import { ERC20TokenListDialog } from '../SNSAdaptor/RRC20TokenListDialog' +import { ERC20TokenListDialog } from '../SNSAdaptor/ERC20TokenListDialog' import { TransactionSnackbar } from '../SNSAdaptor/TransactionSnackbar' import { RestoreLegacyWalletDialog } from '../SNSAdaptor/RestoreLegacyWalletDialog' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/RRC20TokenListDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ERC20TokenListDialog/index.tsx similarity index 100% rename from packages/mask/src/plugins/Wallet/SNSAdaptor/RRC20TokenListDialog/index.tsx rename to packages/mask/src/plugins/Wallet/SNSAdaptor/ERC20TokenListDialog/index.tsx diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx new file mode 100644 index 000000000000..777f33546ccb --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -0,0 +1,18 @@ +import { useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor } from '@masknet/plugin-infra' +import { PLUGIN_ID as EVM_PLUGIN_ID } from '../../../EVM/constants' +import { ProviderTab } from './ProviderTab' + +export interface PluginProviderRenderProps {} + +export const PluginProviderRender = function (props: PluginProviderRenderProps) { + const tabs = [...useActivatedPluginsSNSAdaptor(), ...useActivatedPluginsDashboard()] + .sort((a, b) => { + if (a.ID === EVM_PLUGIN_ID) return -1 + if (b.ID === EVM_PLUGIN_ID) return 1 + return 1 + }) + .map((plugin) => plugin.SelectProviderDialogEntry!) + .filter(Boolean) + + return +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx new file mode 100644 index 000000000000..751a4324d93f --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx @@ -0,0 +1,43 @@ +import { useState, ReactNode } from 'react' +import { Box, Tab, Tabs } from '@mui/material' +import { makeStyles } from '@masknet/theme' +import { ProviderTabPanel } from './ProviderTabPanel' + +const useStyles = makeStyles()((theme) => ({ + root: {}, + tabs: { + width: 80, + }, + tab: { + maxWidth: '100%', + minWidth: 0, + }, +})) + +export interface ProviderTabProps { + tabs: { + name: ReactNode + icon: ReactNode + panel: ReactNode + }[] +} + +export function ProviderTab(props: ProviderTabProps) { + const { classes } = useStyles() + const [value, setValue] = useState(0) + return ( + + setValue(newValue)}> + {props.tabs.map((x, i) => ( + + ))} + + {props.tabs.map((x, i) => (value === i ? {x.panel} : null))} + + ) +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx new file mode 100644 index 000000000000..6386d56c6259 --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx @@ -0,0 +1,21 @@ +import type { ReactNode } from 'react' +import { Box } from '@mui/material' +import { makeStyles } from '@masknet/theme' + +const useStyles = makeStyles()((theme) => ({ + root: { + flex: 1, + minHeight: 300, + padding: theme.spacing(2), + overflow: 'auto', + }, +})) + +export interface ProviderTabPanelProps { + children: ReactNode +} + +export function ProviderTabPanel(props: ProviderTabPanelProps) { + const { classes } = useStyles() + return {props.children} +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 8b8cb425fae0..ea53e7ecf0dc 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,94 +1,21 @@ -import { useCallback, useEffect, useState } from 'react' -import { useAsync } from 'react-use' -import { getMaskColor, makeStyles } from '@masknet/theme' -import { Box, DialogContent, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' -import { useValueRef, useRemoteControlledDialog, useStylesExtends, NetworkIcon } from '@masknet/shared' -import { unreachable } from '@dimensiondev/kit' -import { SuccessIcon } from '@masknet/icons' -import { getChainIdFromNetworkType, ProviderType, useAccount, useChainId, useWallets } from '@masknet/web3-shared-evm' -import { useHistory } from 'react-router-dom' -import classnames from 'classnames' +import { useEffect } from 'react' +import { makeStyles } from '@masknet/theme' +import { DialogContent } from '@mui/material' +import { useRemoteControlledDialog, useStylesExtends } from '@masknet/shared' import { useI18N } from '../../../../utils/i18n-next-ui' -import { Provider } from '../Provider' -import { MetaMaskIcon } from '../../../../resources/MetaMaskIcon' -import { MaskIcon } from '../../../../resources/MaskIcon' -import { WalletConnectIcon } from '../../../../resources/WalletConnectIcon' -import { WalletMessages, WalletRPC } from '../../messages' +import { WalletMessages } from '../../messages' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' -import { currentNetworkSettings, currentProviderSettings } from '../../settings' -import { Flags, hasNativeAPI, nativeAPI } from '../../../../utils' -import Services from '../../../../extension/service' -import { PopupRoutes } from '../../../../extension/popups' +import { hasNativeAPI, nativeAPI } from '../../../../utils' +import { PluginProviderRender } from './PluginProviderRender' const useStyles = makeStyles()((theme) => ({ - paper: { - width: '750px !important', - maxWidth: 'unset', - }, content: { - padding: theme.spacing(4, 4.5, 2), - }, - step: { - flexGrow: 1, - marginTop: 21, - '&:first-child': { - marginTop: 0, + padding: theme.spacing(0), + scrollbarWidth: 'none', + '&::-webkit-scrollbar': { + display: 'none', }, }, - stepTitle: { - fontSize: 19, - fontWeight: 'bold', - }, - stepContent: { - marginTop: 21, - }, - networkDisabled: { - opacity: 0.5, - }, - networkList: { - display: 'flex', - gap: 32, - }, - networkItem: { - width: 'auto', - padding: 0, - }, - iconWrapper: { - position: 'relative', - cursor: 'pointer', - height: 48, - width: 48, - borderRadius: 48, - backgroundColor: getMaskColor(theme).twitterBackground, - }, - networkIcon: { - backgroundColor: getMaskColor(theme).twitterBackground, - }, - checkedBadge: { - position: 'absolute', - right: 0, - bottom: 0, - width: 14, - height: 14, - background: '#fff', - borderRadius: '50%', - }, - alert: { - fontSize: 12, - display: 'flex', - alignItems: 'center', - marginTop: theme.spacing(1), - }, - grid: { - width: '100%', - margin: theme.spacing(2, 0, 0), - }, - providerIcon: { - fontSize: 45, - }, - tip: { - fontSize: 12, - }, })) interface SelectProviderDialogUIProps extends withClasses {} @@ -97,10 +24,6 @@ function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { const { t } = useI18N() const classes = useStylesExtends(useStyles(), props) - const account = useAccount() - const chainId = useChainId() - const history = useHistory() - //#region remote controlled dialog logic const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) //#endregion @@ -112,144 +35,13 @@ function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { }, [open]) //#endregion - //#region wallet status dialog - const { openDialog: openWalletStatusDialog } = useRemoteControlledDialog( - WalletMessages.events.walletStatusDialogUpdated, - ) - //#endregion - - //#region select wallet dialog - const { setDialog: setSelectWalletDialog } = useRemoteControlledDialog( - WalletMessages.events.selectWalletDialogUpdated, - ) - //#endregion - - //#region connect wallet dialog - const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( - WalletMessages.events.connectWalletDialogUpdated, - ) - //#endregion - - //#region wallet connect QR code dialog - const { setDialog: setWalletConnectDialog } = useRemoteControlledDialog( - WalletMessages.events.walletConnectQRCodeDialogUpdated, - ) - //#endregion - - const wallets = useWallets(ProviderType.MaskWallet) - const selectedNetworkType = useValueRef(currentNetworkSettings) - const selectedProviderType = useValueRef(currentProviderSettings) - - //#region undetermined network type - const [undeterminedNetworkType, setUndeterminedNetworkType] = useState(selectedNetworkType) - useEffect(() => { - if (!open) return - setUndeterminedNetworkType(selectedNetworkType) - }, [open]) - //#endregion - - const { value: networks } = useAsync(async () => WalletRPC.getSupportedNetworks(), []) - - const onConnectProvider = useCallback( - async (providerType: ProviderType) => { - closeDialog() - - switch (providerType) { - case ProviderType.MaskWallet: - await Services.Helper.openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { - chainId: getChainIdFromNetworkType(undeterminedNetworkType), - }) - break - case ProviderType.MetaMask: - case ProviderType.WalletConnect: - setConnectWalletDialog({ - open: true, - providerType, - networkType: undeterminedNetworkType, - }) - break - case ProviderType.CustomNetwork: - throw new Error('To be implemented.') - default: - unreachable(providerType) - } - }, - [ - account, - chainId, - wallets, - history, - closeDialog, - undeterminedNetworkType, - selectedProviderType, - openWalletStatusDialog, - setSelectWalletDialog, - setWalletConnectDialog, - ], - ) - // not available for the native app if (hasNativeAPI) return null return ( - - - 1. Choose Network - - - {networks?.map((network) => ( - { - setUndeterminedNetworkType(network) - }}> -
- - {undeterminedNetworkType === network && ( - - )} -
-
- ))} -
-
- - - 2. Choose Wallet - - - - } - name="Mask Network" - onClick={() => onConnectProvider(ProviderType.MaskWallet)} - /> - - {Flags.metamask_support_enabled ? ( - - } - name="MetaMask" - onClick={() => onConnectProvider(ProviderType.MetaMask)} - /> - - ) : null} - - } - name="WalletConnect" - onClick={() => onConnectProvider(ProviderType.WalletConnect)} - /> - - - +
) diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx index 5c2ea518c432..ce2c592b1f6a 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useState, useCallback } from 'react' import { useHistory } from 'react-router-dom' import { Button, DialogActions, DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' @@ -10,7 +10,6 @@ import { WalletMessages, WalletRPC } from '../messages' import { WalletInList } from '../../../components/shared/SelectWallet/WalletInList' import Services from '../../../extension/service' import { InjectedDialog } from '../../../components/shared/InjectedDialog' -import { useState } from 'react' const useStyles = makeStyles()({ content: { diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx index 7d17037e5f5a..1cb4af28f83e 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx @@ -12,7 +12,7 @@ import { ConnectWalletDialog } from './ConnectWalletDialog' import { useStartWatchChainState } from '../hooks/useStartWatchChainState' import { WalletRiskWarningDialog } from './RiskWarningDialog' import { GasSettingDialog } from './GasSettingDialog' -import { ERC20TokenListDialog } from './RRC20TokenListDialog' +import { ERC20TokenListDialog } from './ERC20TokenListDialog' import { TransactionSnackbar } from './TransactionSnackbar' import { RestoreLegacyWalletDialog } from './RestoreLegacyWalletDialog' diff --git a/packages/mask/src/utils/flags.ts b/packages/mask/src/utils/flags.ts index d611ca46c96e..00ff6ba16d42 100644 --- a/packages/mask/src/utils/flags.ts +++ b/packages/mask/src/utils/flags.ts @@ -50,6 +50,7 @@ export const Flags = { polygon_enabled: true, arbitrum_enabled: true, xdai_enabled: true, + flow_enabled: true, nft_airdrop_enabled: false, //#region Functionality missing / broken diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 36f88ae0a7dc..5c684771a971 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -1,7 +1,8 @@ +import type React from 'react' +import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' import type { ChainId } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' -import type { Option, Result } from 'ts-results' export namespace Plugin { /** @@ -181,6 +182,8 @@ export namespace Plugin.SNSAdaptor { GlobalInjection?: InjectUI<{}> /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry + /** This UI will be an entry of network in the Select Provider Dialog. */ + SelectProviderDialogEntry?: SelectProviderDialogEntry /** This UI will be use when there is known badges. */ CompositionDialogMetadataBadgeRender?: CompositionMetadataBadgeRender /** This UI will be rendered as an entry in the toolbar (if the SNS has a Toolbar support) */ @@ -194,6 +197,7 @@ export namespace Plugin.SNSAdaptor { * - Custom type: Fallback choice if the dialog type cannot do what you want to do. */ export type CompositionDialogEntry = CompositionDialogEntryCustom | CompositionDialogEntryDialog + export interface CompositionDialogEntryCustom { /** * A label that will be rendered in the CompositionDialog as a chip. @@ -218,6 +222,12 @@ export namespace Plugin.SNSAdaptor { */ keepMounted?: boolean } + + export interface SelectProviderDialogEntry { + name: React.ReactNode + icon: React.ReactNode + panel: React.ReactNode + } export interface CompositionDialogEntry_DialogProps { open: boolean onClose(): void @@ -268,6 +278,8 @@ export namespace Plugin.Dashboard { export interface Definition extends Shared.DefinitionDeferred { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> + /** This UI will be an entry of network in the Select Provider Dialog. */ + SelectProviderDialogEntry?: Plugin.SNSAdaptor.SelectProviderDialogEntry } } diff --git a/packages/plugins/Flow/package.json b/packages/plugins/Flow/package.json new file mode 100644 index 000000000000..70533b129893 --- /dev/null +++ b/packages/plugins/Flow/package.json @@ -0,0 +1,17 @@ +{ + "name": "@masknet/plugin-flow", + "private": true, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "@masknet/plugin-infra": "workspace:*", + "@masknet/shared": "workspace:*", + "@masknet/shared-base": "workspace:*", + "@masknet/theme": "workspace:*", + "@masknet/icons": "workspace:*", + "@masknet/web3-shared-flow": "workspace:*", + "@onflow/fcl": "^0.0.77", + "bignumber.js": "^9.0.1", + "react-use": "^17.3.1" + } +} diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx new file mode 100644 index 000000000000..d4ce558cd055 --- /dev/null +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -0,0 +1,16 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../../base' +import { PluginIcon } from '../components/PluginIcon' +import { PluginPanel } from '../components/PluginPanel' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal) {}, + SelectProviderDialogEntry: { + name: 'Flow', + icon: , + panel: , + }, +} + +export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx new file mode 100644 index 000000000000..d4ce558cd055 --- /dev/null +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -0,0 +1,16 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../../base' +import { PluginIcon } from '../components/PluginIcon' +import { PluginPanel } from '../components/PluginPanel' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal) {}, + SelectProviderDialogEntry: { + name: 'Flow', + icon: , + panel: , + }, +} + +export default sns diff --git a/packages/plugins/Flow/src/UI/components/AccountOverview.tsx b/packages/plugins/Flow/src/UI/components/AccountOverview.tsx new file mode 100644 index 000000000000..01c47df04cd9 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/AccountOverview.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface AccountOverviewProps {} + +export function AccountOverview(props: AccountOverviewProps) { + return The current account overview. +} diff --git a/packages/plugins/Flow/src/UI/components/AssetList.tsx b/packages/plugins/Flow/src/UI/components/AssetList.tsx new file mode 100644 index 000000000000..340222116c48 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/AssetList.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface AssetListProps {} + +export function AssetList(props: AssetListProps) { + return No Asset. +} diff --git a/packages/plugins/Flow/src/UI/components/CollectionList.tsx b/packages/plugins/Flow/src/UI/components/CollectionList.tsx new file mode 100644 index 000000000000..207993efb99c --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/CollectionList.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface CollectionListProps {} + +export function CollectionList(props: CollectionListProps) { + return No Collection. +} diff --git a/packages/plugins/Flow/src/UI/components/DashboardAssetsTab.tsx b/packages/plugins/Flow/src/UI/components/DashboardAssetsTab.tsx new file mode 100644 index 000000000000..8bcec1fff6b5 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/DashboardAssetsTab.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface DashboardAssetsTabProps {} + +export function DashboardAssetsTab(props: DashboardAssetsTabProps) { + return Dashboard Assets Tab. +} diff --git a/packages/plugins/Flow/src/UI/components/DashboardHistoryTab.tsx b/packages/plugins/Flow/src/UI/components/DashboardHistoryTab.tsx new file mode 100644 index 000000000000..1b3a1295b76a --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/DashboardHistoryTab.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface DashboardHistoryTabProps {} + +export function DashboardHistoryTab(props: DashboardHistoryTabProps) { + return Dashboard History Tab. +} diff --git a/packages/plugins/Flow/src/UI/components/DashboardOverview.tsx b/packages/plugins/Flow/src/UI/components/DashboardOverview.tsx new file mode 100644 index 000000000000..94fc5b2816a4 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/DashboardOverview.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface DashboardOverviewProps {} + +export function DashboardOverview(props: DashboardOverviewProps) { + return Dashboard Overview. +} diff --git a/packages/plugins/Flow/src/UI/components/DashboardTransferTab.tsx b/packages/plugins/Flow/src/UI/components/DashboardTransferTab.tsx new file mode 100644 index 000000000000..b39faeede170 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/DashboardTransferTab.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface DashboardTransferTabProps {} + +export function DashboardTransferTab(props: DashboardTransferTabProps) { + return Dashboard Transfer Tab. +} diff --git a/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx b/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx new file mode 100644 index 000000000000..de68b5b644ec --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx @@ -0,0 +1,12 @@ +import type { ChainId, ProviderType } from '@masknet/web3-shared-flow' + +export interface NetworkIconProps { + size: number + chainId: ChainId + // if exists, a small provider icon will add a provider cion on the right bottom side + providerType?: ProviderType +} + +export function NetworkIcon(props: NetworkIconProps) { + return <> +} diff --git a/packages/plugins/Flow/src/UI/components/PluginIcon.tsx b/packages/plugins/Flow/src/UI/components/PluginIcon.tsx new file mode 100644 index 000000000000..62f73c91e404 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/PluginIcon.tsx @@ -0,0 +1,16 @@ +import { makeStyles } from '@masknet/theme' + +const useStyles = makeStyles()({ + image: { + width: 24, + height: 24, + }, +}) + +export interface PluginIconProps {} + +export function PluginIcon(props: PluginIconProps) { + const { classes } = useStyles() + const iconURL = new URL('../../assets/flow.png', import.meta.url).toString() + return +} diff --git a/packages/plugins/Flow/src/UI/components/PluginPanel.tsx b/packages/plugins/Flow/src/UI/components/PluginPanel.tsx new file mode 100644 index 000000000000..24e4f99ea922 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/PluginPanel.tsx @@ -0,0 +1,104 @@ +import { useCallback } from 'react' +import { useCopyToClipboard } from 'react-use' +import { CopyIcon } from '@masknet/icons' +import { makeStyles } from '@masknet/theme' +import { Box, Button, IconButton, Typography } from '@mui/material' +import { useAccount, useFCL } from '@masknet/web3-shared-flow' +import { useI18N } from '../../locales' + +const useStyles = makeStyles()((theme) => ({ + root: { + display: 'flex', + flexDirection: 'column', + height: 350, + padding: theme.spacing(0, 2, 0, 3), + }, + main: { + display: 'flex', + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'flex-start', + }, + copy: { + width: 16, + height: 16, + cursor: 'pointer', + stroke: theme.palette.text.secondary, + }, + lable: { + fontSize: 18, + }, + balance: { + fontSize: 24, + }, + image: { + width: 24, + height: 24, + }, +})) + +export interface PluginPanelProps {} + +export function PluginPanel(props: PluginPanelProps) { + const t = useI18N() + const { classes } = useStyles() + + const fcl = useFCL() + const { value: account } = useAccount() + const [, copyToClipboard] = useCopyToClipboard() + + const onLogIn = useCallback(() => fcl.logIn(), [fcl]) + const onSignUp = useCallback(() => fcl.signUp(), [fcl]) + const onLogOut = useCallback(() => fcl.unauthenticate(), [fcl]) + + console.log(account) + + if (account?.address) + return ( + + + + + Profile Information + + + + {account.address} + copyToClipboard(account.address)}> + + + + + + {account.balance} FLOW + + + + + + + + ) + + return ( + + + {t.card_state_text_no_profile()} + + + + + + + ) +} diff --git a/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx b/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx new file mode 100644 index 000000000000..3c257bc5d527 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx @@ -0,0 +1,11 @@ +import { ProviderType, resolveProviderName } from '@masknet/web3-shared-flow' +import { Typography } from '@mui/material' + +export interface ProviderIconProps { + size: number + providerType: ProviderType +} + +export function ProviderIcon(props: ProviderIconProps) { + return {resolveProviderName(props.providerType)} +} diff --git a/packages/plugins/Flow/src/UI/components/TransactionList.tsx b/packages/plugins/Flow/src/UI/components/TransactionList.tsx new file mode 100644 index 000000000000..b6c4590a1e68 --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/TransactionList.tsx @@ -0,0 +1,7 @@ +import { Typography } from '@mui/material' + +export interface TransactionListProps {} + +export function TransactionList(props: TransactionListProps) { + return No transaction. +} diff --git a/packages/plugins/Flow/src/Worker/index.ts b/packages/plugins/Flow/src/Worker/index.ts new file mode 100644 index 000000000000..824d930b57e1 --- /dev/null +++ b/packages/plugins/Flow/src/Worker/index.ts @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' +import '../messages' + +const worker: Plugin.Worker.Definition = { + ...base, + init(signal) {}, +} +export default worker diff --git a/packages/plugins/Flow/src/apis/index.ts b/packages/plugins/Flow/src/apis/index.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/plugins/Flow/src/apis/index.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/plugins/Flow/src/assets/flow.png b/packages/plugins/Flow/src/assets/flow.png new file mode 100644 index 0000000000000000000000000000000000000000..2ea4ccf2f60fc3c650efcafe1ba189f85774a626 GIT binary patch literal 5078 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 literal 0 HcmV?d00001 diff --git a/packages/plugins/Flow/src/base.ts b/packages/plugins/Flow/src/base.ts new file mode 100644 index 000000000000..60560f345a8c --- /dev/null +++ b/packages/plugins/Flow/src/base.ts @@ -0,0 +1,17 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { languages } from './locales' +import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION } from './constants' + +export const base: Plugin.Shared.Definition = { + ID: PLUGIN_ID, + icon: PLUGIN_ICON, + name: { fallback: PLUGIN_NAME }, + description: { fallback: PLUGIN_DESCRIPTION }, + publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, + enableRequirement: { + architecture: { app: true, web: true }, + networks: { type: 'opt-out', networks: {} }, + target: 'stable', + }, + i18n: languages, +} diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts new file mode 100644 index 000000000000..fa43fbed6e35 --- /dev/null +++ b/packages/plugins/Flow/src/constants.ts @@ -0,0 +1,5 @@ +export const PLUGIN_META_KEY = 'com.maskbook.flow' +export const PLUGIN_ID = 'com.maskbook.flow' +export const PLUGIN_NAME = 'Flow Chain' +export const PLUGIN_ICON = 'F' +export const PLUGIN_DESCRIPTION = '' diff --git a/packages/plugins/Flow/src/helpers/index.ts b/packages/plugins/Flow/src/helpers/index.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/plugins/Flow/src/helpers/index.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/plugins/Flow/src/hooks/index.ts b/packages/plugins/Flow/src/hooks/index.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/plugins/Flow/src/hooks/index.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/plugins/Flow/src/index.ts b/packages/plugins/Flow/src/index.ts new file mode 100644 index 000000000000..48ab76cba202 --- /dev/null +++ b/packages/plugins/Flow/src/index.ts @@ -0,0 +1,23 @@ +import { registerPlugin } from '@masknet/plugin-infra' +import { base } from './base' + +registerPlugin({ + ...base, + SNSAdaptor: { + load: () => import('./UI/SNSAdaptor'), + hotModuleReload: (hot) => + import.meta.webpackHot && + import.meta.webpackHot.accept('./UI/SNSAdaptor', () => hot(import('./UI/SNSAdaptor'))), + }, + Dashboard: { + load: () => import('./UI/Dashboard'), + hotModuleReload: (hot) => + import.meta.webpackHot && + import.meta.webpackHot.accept('./UI/Dashboard', () => hot(import('./UI/Dashboard'))), + }, + Worker: { + load: () => import('./Worker'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Worker', () => hot(import('./Worker'))), + }, +}) diff --git a/packages/plugins/Flow/src/locales/en-US.json b/packages/plugins/Flow/src/locales/en-US.json new file mode 100644 index 000000000000..ee5e3125b8c9 --- /dev/null +++ b/packages/plugins/Flow/src/locales/en-US.json @@ -0,0 +1,6 @@ +{ + "button_log_in": "Log In", + "button_log_out": "Log Out", + "button_sign_up": "Sign Up", + "card_state_text_no_profile": "No Profile" +} diff --git a/packages/plugins/Flow/src/locales/index.ts b/packages/plugins/Flow/src/locales/index.ts new file mode 100644 index 000000000000..a667a3f3a7d4 --- /dev/null +++ b/packages/plugins/Flow/src/locales/index.ts @@ -0,0 +1,12 @@ +// This file is auto generated. DO NOT EDIT +// Run `npx gulp sync-languages` to regenerate. +// Default fallback language in a family of languages are chosen by the alphabet order +// To overwrite this, please overwrite packages/scripts/src/locale-kit-next/index.ts +import en_US from './en-US.json' +import zh_TW from './zh-TW.json' + +export * from './i18n_generated' +export const languages = { + en: en_US, + zh: zh_TW, +} diff --git a/packages/plugins/Flow/src/locales/zh-TW.json b/packages/plugins/Flow/src/locales/zh-TW.json new file mode 100644 index 000000000000..2ebdd61072d6 --- /dev/null +++ b/packages/plugins/Flow/src/locales/zh-TW.json @@ -0,0 +1,6 @@ +{ + "button_log_in": "", + "button_log_out": "", + "button_sign_up": "", + "card_state_text_no_profile": "" +} diff --git a/packages/plugins/Flow/src/messages.ts b/packages/plugins/Flow/src/messages.ts new file mode 100644 index 000000000000..28e50916bf1d --- /dev/null +++ b/packages/plugins/Flow/src/messages.ts @@ -0,0 +1,7 @@ +import { createPluginMessage, createPluginRPC } from '@masknet/plugin-infra' +import { PLUGIN_ID } from './constants' + +if (import.meta.webpackHot) import.meta.webpackHot.accept() +const FlowMessage = createPluginMessage(PLUGIN_ID) + +export const FlowRPC = createPluginRPC(PLUGIN_ID, () => import('./services'), FlowMessage.rpc) diff --git a/packages/plugins/Flow/src/services.ts b/packages/plugins/Flow/src/services.ts new file mode 100644 index 000000000000..5914b704d67f --- /dev/null +++ b/packages/plugins/Flow/src/services.ts @@ -0,0 +1 @@ +export * from './apis' diff --git a/packages/plugins/Flow/src/types.ts b/packages/plugins/Flow/src/types.ts new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/packages/plugins/Flow/src/types.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/plugins/Flow/tsconfig.json b/packages/plugins/Flow/tsconfig.json new file mode 100644 index 000000000000..1931aea5c1a4 --- /dev/null +++ b/packages/plugins/Flow/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/", + "outDir": "./dist/", + "tsBuildInfoFile": "./dist/.tsbuildinfo", + "resolveJsonModule": true + }, + "include": ["./src", "./src/**/*.json"], + "references": [ + { "path": "../../plugin-infra" }, + { "path": "../../shared" }, + { "path": "../../shared-base" }, + { "path": "../../theme" }, + { "path": "../../web3-shared/flow" } + ] +} diff --git a/packages/plugins/tsconfig.json b/packages/plugins/tsconfig.json index 248a9cf19849..a52009a21532 100644 --- a/packages/plugins/tsconfig.json +++ b/packages/plugins/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../../tsconfig.json", - "references": [{ "path": "./example/" }, { "path": "./Wallet/" }] + "references": [{ "path": "./example/" }, { "path": "./Flow/" }, { "path": "./Wallet/" }] } diff --git a/packages/web3-constants/compile-constants.ts b/packages/web3-constants/compile-constants.ts index e212fab9c60f..27b5cbc6bb91 100644 --- a/packages/web3-constants/compile-constants.ts +++ b/packages/web3-constants/compile-constants.ts @@ -55,3 +55,5 @@ compileConstants(path.join(__dirname, 'evm'), [ ]) compileConstants(path.join(__dirname, 'solana'), ['mainnet-beta', 'testnet', 'devnet']) + +compileConstants(path.join(__dirname, 'flow'), ['Mainnet', 'Testnet']) diff --git a/packages/web3-constants/flow/auth.json b/packages/web3-constants/flow/auth.json new file mode 100644 index 000000000000..4696ab57496f --- /dev/null +++ b/packages/web3-constants/flow/auth.json @@ -0,0 +1,14 @@ +{ + "ACCESS_NODE_API": { + "Mainnet": "https://flow-access-mainnet.portto.io", + "Testnet": "https://access-testnet.onflow.org" + }, + "DISCOVERY_WALLET": { + "Mainnet": "https://flow-wallet.blocto.app/authn", + "Testnet": "https://flow-wallet-testnet.blocto.app/authn" + }, + "CHALLENGE_HANDSHAKE": { + "Mainnet": "https://flow-wallet.blocto.app/authn", + "Testnet": "https://flow-wallet-testnet.blocto.app/authn" + } +} diff --git a/packages/web3-kit/package.json b/packages/web3-kit/package.json new file mode 100644 index 000000000000..6d0062360c10 --- /dev/null +++ b/packages/web3-kit/package.json @@ -0,0 +1,6 @@ +{ + "name": "@masknet/web3-kit", + "private": true, + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts" +} diff --git a/packages/web3-kit/src/helpers/constants.ts b/packages/web3-kit/src/helpers/constants.ts new file mode 100644 index 000000000000..1178259f5dc8 --- /dev/null +++ b/packages/web3-kit/src/helpers/constants.ts @@ -0,0 +1,68 @@ +import { useMemo } from 'react' +import type { Primitive } from '../types' + +type ChainId = number + +type ChainIdEnum = { + [key in ChainId]: string +} & { + [key in 'Mainnet']: number +} + +export type Constant = { + [key in 'Mainnet']?: Primitive | Primitive[] +} + +export type Constants = Record + +export function transform( + chainIdEnum: C, + constants: T, + environment: Record = {}, +) { + type Entries = { [key in keyof T]?: T[key]['Mainnet'] } + return (chainId: ChainId = 1) => { + const chainName = chainIdEnum[chainId] as 'Mainnet' + // unknown chain id + if (!chainName) return Object.freeze({}) as Entries + const entries = Object.keys(constants).map((name: keyof T) => { + let value = constants[name][chainName] + if (Array.isArray(value)) { + value = value.map((item) => { + if (typeof item === 'string') { + return replaceAll(item, environment) + } + return item + }) + } else if (typeof value === 'string') { + value = replaceAll(value, environment) + } + return [name, value] as [string, Primitive | Primitive[]] + }) + return Object.freeze(Object.fromEntries(entries)) as Entries + } +} + +export function transformFromJSON( + chainIdEnum: ChainIdEnum, + json: string, + fallbackConstants: T, + environment: Record = {}, +) { + try { + const constants = JSON.parse(json) as T + return transform(chainIdEnum, constants, environment) + } catch { + return transform(chainIdEnum, fallbackConstants, environment) + } +} + +export function hookTransform(getConstants: (chainId: ChainId) => Partial) { + return function useConstants(chainId: ChainId) { + return useMemo(() => getConstants(chainId), [chainId]) + } +} + +function replaceAll(input: string, values: Record) { + return input.replace(/\${([^}]+)}/g, (match, p1) => values[p1] ?? match) +} diff --git a/packages/web3-kit/src/helpers/index.ts b/packages/web3-kit/src/helpers/index.ts new file mode 100644 index 000000000000..84ac0192f505 --- /dev/null +++ b/packages/web3-kit/src/helpers/index.ts @@ -0,0 +1,2 @@ +export * from './constants' +export * from './lookupTable' diff --git a/packages/web3-kit/src/helpers/lookupTable.ts b/packages/web3-kit/src/helpers/lookupTable.ts new file mode 100644 index 000000000000..10a77a548bae --- /dev/null +++ b/packages/web3-kit/src/helpers/lookupTable.ts @@ -0,0 +1,7 @@ +export function createLookupTableResolver(map: Record, fallback: T | ((key: K) => T)) { + function resolveFallback(key: K) { + if (typeof fallback === 'function') return (fallback as (key: K) => T)(key) + return fallback + } + return (key: K) => map[key] ?? resolveFallback(key) +} diff --git a/packages/web3-kit/src/index.ts b/packages/web3-kit/src/index.ts new file mode 100644 index 000000000000..b2a4c7512849 --- /dev/null +++ b/packages/web3-kit/src/index.ts @@ -0,0 +1 @@ +export * from './helpers' diff --git a/packages/web3-kit/src/types.ts b/packages/web3-kit/src/types.ts new file mode 100644 index 000000000000..e190a7b90b77 --- /dev/null +++ b/packages/web3-kit/src/types.ts @@ -0,0 +1,2 @@ +// bigint is not in our list. iOS doesn't support that. +export type Primitive = string | number | boolean | symbol | undefined | null diff --git a/packages/web3-kit/tsconfig.json b/packages/web3-kit/tsconfig.json new file mode 100644 index 000000000000..194f92619e6e --- /dev/null +++ b/packages/web3-kit/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/", + "outDir": "./dist/src/", + "tsBuildInfoFile": "./dist/src.tsbuildinfo" + }, + "include": ["./src", "./src/**/*.json"] +} diff --git a/packages/web3-shared/flow/constants/index.ts b/packages/web3-shared/flow/constants/index.ts new file mode 100644 index 000000000000..2d1e71448ddf --- /dev/null +++ b/packages/web3-shared/flow/constants/index.ts @@ -0,0 +1,6 @@ +import Auth from '@masknet/web3-constants/flow/auth.json' +import { hookTransform, transform } from '@masknet/web3-kit' +import { ChainId } from '../types' + +export const getAuthConstants = transform(ChainId, Auth) +export const useAuthConstants = hookTransform(getAuthConstants) diff --git a/packages/web3-shared/flow/env.d.ts b/packages/web3-shared/flow/env.d.ts new file mode 100644 index 000000000000..f717326649d1 --- /dev/null +++ b/packages/web3-shared/flow/env.d.ts @@ -0,0 +1,27 @@ +declare module '@onflow/fcl' { + export interface User { + addr: string | null + f_type: 'User' + f_vsn: string + loggedIn: boolean | null + } + + export interface Account { + address: string + balance: string + code: string + } + + export const config: (setup: Record) => {} + export const currentUser: () => { + subscribe: (callback: (user: User) => void) => void + } + export const logIn: () => {} + export const logOut: () => {} + export const signUp: () => {} + export const unauthenticate: () => {} + + export const send: (data: string[]) => Promise + export const script: (text: string) => string + export const getAccount: (address: string) => string +} diff --git a/packages/web3-shared/flow/hooks/index.ts b/packages/web3-shared/flow/hooks/index.ts new file mode 100644 index 000000000000..8128752358cb --- /dev/null +++ b/packages/web3-shared/flow/hooks/index.ts @@ -0,0 +1,7 @@ +export * from './useAccount' +export * from './useBalance' +export * from './useChainId' +export * from './useChainConfig' +export * from './useCurrentUser' +export * from './useFCL' +export * from './useScript' diff --git a/packages/web3-shared/flow/hooks/useAccount.ts b/packages/web3-shared/flow/hooks/useAccount.ts new file mode 100644 index 000000000000..7922b87ce3e1 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useAccount.ts @@ -0,0 +1,13 @@ +import type { Account } from '@onflow/fcl' +import { useAsyncRetry } from 'react-use' +import { useCurrentUser, useFCL } from '.' + +export function useAccount() { + const fcl = useFCL() + const currentUser = useCurrentUser() + return useAsyncRetry(async () => { + if (!currentUser?.addr) return null + const { account } = await fcl.send([fcl.getAccount(currentUser.addr)]) + return account as Account + }, [currentUser?.addr, fcl]) +} diff --git a/packages/web3-shared/flow/hooks/useBalance.ts b/packages/web3-shared/flow/hooks/useBalance.ts new file mode 100644 index 000000000000..e8fd006c9d51 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useBalance.ts @@ -0,0 +1,9 @@ +import { useAccount } from './useAccount' +import { useMemo } from 'react' + +export function useBalance() { + const { value: account } = useAccount() + return useMemo(() => { + return account?.balance ?? '0' + }, [account?.balance]) +} diff --git a/packages/web3-shared/flow/hooks/useChainConfig.ts b/packages/web3-shared/flow/hooks/useChainConfig.ts new file mode 100644 index 000000000000..d1f2ef3cf014 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useChainConfig.ts @@ -0,0 +1,14 @@ +import { useMemo } from 'react' +import type { ChainId } from '../types' +import { useAuthConstants } from '../constants' + +export function useChainConfig(chainId: ChainId) { + const authConstants = useAuthConstants(chainId) + + return useMemo(() => { + return { + 'accessNode.api': authConstants.ACCESS_NODE_API, + 'discovery.wallet': authConstants.DISCOVERY_WALLET, + } + }, [authConstants]) +} diff --git a/packages/web3-shared/flow/hooks/useChainId.ts b/packages/web3-shared/flow/hooks/useChainId.ts new file mode 100644 index 000000000000..21a4b4e0fedb --- /dev/null +++ b/packages/web3-shared/flow/hooks/useChainId.ts @@ -0,0 +1,5 @@ +import { ChainId } from '../types' + +export function useChainId() { + return ChainId.Testnet +} diff --git a/packages/web3-shared/flow/hooks/useCurrentUser.ts b/packages/web3-shared/flow/hooks/useCurrentUser.ts new file mode 100644 index 000000000000..26030ca65549 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useCurrentUser.ts @@ -0,0 +1,12 @@ +import { useEffect, useState } from 'react' +import type { User } from '@onflow/fcl' +import { useFCL } from './' + +export function useCurrentUser() { + const fcl = useFCL() + const [user, setUser] = useState() + + useEffect(() => fcl.currentUser().subscribe(setUser), []) + + return user +} diff --git a/packages/web3-shared/flow/hooks/useFCL.ts b/packages/web3-shared/flow/hooks/useFCL.ts new file mode 100644 index 000000000000..850707efd72c --- /dev/null +++ b/packages/web3-shared/flow/hooks/useFCL.ts @@ -0,0 +1,19 @@ +import { useMemo } from 'react' +import * as fcl from '@onflow/fcl' +import { useAuthConstants } from '../constants' +import { useChainId } from '.' + +export function useFCL() { + const chainId = useChainId() + const authConstants = useAuthConstants(chainId) + return useMemo(() => { + fcl.config({ + 'accessNode.api': authConstants.ACCESS_NODE_API, + 'app.detail.title': 'Mask Network', + 'app.detail.icon': + 'https://dimensiondev.github.io/Maskbook-VI/assets/Logo/MB--Logo--Geo--ForceCircle--Blue.svg', + 'challenge.handshake': authConstants.CHALLENGE_HANDSHAKE, + }) + return fcl + }, [authConstants]) +} diff --git a/packages/web3-shared/flow/hooks/useScript.ts b/packages/web3-shared/flow/hooks/useScript.ts new file mode 100644 index 000000000000..774511246854 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useScript.ts @@ -0,0 +1,10 @@ +import { useAsyncRetry } from 'react-use' +import { useFCL } from './' + +export function useScript(script: string) { + const fcl = useFCL() + + return useAsyncRetry(async () => { + return fcl.send([fcl.script(script)]) + }, [fcl, script]) +} diff --git a/packages/web3-shared/flow/index.ts b/packages/web3-shared/flow/index.ts new file mode 100644 index 000000000000..b0d95eccd958 --- /dev/null +++ b/packages/web3-shared/flow/index.ts @@ -0,0 +1,3 @@ +export * from './hooks' +export * from './types' +export * from './pipes' diff --git a/packages/web3-shared/flow/package.json b/packages/web3-shared/flow/package.json new file mode 100644 index 000000000000..1614ee07f678 --- /dev/null +++ b/packages/web3-shared/flow/package.json @@ -0,0 +1,13 @@ +{ + "name": "@masknet/web3-shared-flow", + "private": true, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "@masknet/web3-constants": "workspace:*", + "@masknet/web3-kit": "workspace:*", + "@onflow/fcl": "^0.0.77", + "@onflow/types": "^0.0.5", + "react-use": "^17.3.1" + } +} diff --git a/packages/web3-shared/flow/pipes/index.ts b/packages/web3-shared/flow/pipes/index.ts new file mode 100644 index 000000000000..2488dcf42474 --- /dev/null +++ b/packages/web3-shared/flow/pipes/index.ts @@ -0,0 +1,37 @@ +import { createLookupTableResolver } from '@masknet/web3-kit' +import { ChainId, ProviderType } from '../types' + +export const resolveChainName = createLookupTableResolver( + { + [ChainId.Mainnet]: 'mainnet', + [ChainId.Testnet]: 'testnet', + }, + () => 'Unknown chain id', +) + +export const resolveProviderName = createLookupTableResolver( + { + [ProviderType.Blocto]: 'Blocto', + [ProviderType.Dapper]: 'Dapper', + [ProviderType.Ledger]: 'Ledger', + }, + () => 'Unknown provider type', +) + +export const resolveLinkOnExplorer = createLookupTableResolver( + { + [ChainId.Mainnet]: 'https://flowscan.org/', + [ChainId.Testnet]: 'https://testnet.flowscan.org/', + }, + () => 'Unknown chain id', +) + +// todo: https://flowscan.org/ +export function resolveTransactionLinkOnExplorer(chainId: ChainId, tx: string) { + return '' +} + +// todo: https://flowscan.org/ +export function resolveAccountLinkOnExplorer(chainId: ChainId, address: string) { + return '' +} diff --git a/packages/web3-shared/flow/tsconfig.json b/packages/web3-shared/flow/tsconfig.json new file mode 100644 index 000000000000..3548636e4fb0 --- /dev/null +++ b/packages/web3-shared/flow/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "rootDir": "./", + "outDir": "../dist/flow", + "tsBuildInfoFile": "../dist/flow.tsbuildinfo" + }, + "include": ["./", "./**/*.json"] +} diff --git a/packages/web3-shared/flow/types.ts b/packages/web3-shared/flow/types.ts new file mode 100644 index 000000000000..166499366a34 --- /dev/null +++ b/packages/web3-shared/flow/types.ts @@ -0,0 +1,10 @@ +export enum ChainId { + Mainnet = 1, + Testnet = 2, +} + +export enum ProviderType { + Blocto = 'Blocto', + Dapper = 'Dapper', + Ledger = 'Ledger', +} diff --git a/packages/web3-shared/tsconfig.json b/packages/web3-shared/tsconfig.json index 13966f6387bb..e24cc618f838 100644 --- a/packages/web3-shared/tsconfig.json +++ b/packages/web3-shared/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../../tsconfig.json", - "references": [{ "path": "./evm/" }, { "path": "./solana/" }] + "references": [{ "path": "./evm/" }, { "path": "./flow/" }, { "path": "./solana/" }] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcac73c33148..b42be6c6969f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,6 +120,7 @@ importers: '@masknet/backup-format': workspace:* '@masknet/icons': workspace:* '@masknet/plugin-example': workspace:* + '@masknet/plugin-flow': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/plugin-wallet': workspace:* '@masknet/public-api': workspace:* @@ -169,6 +170,7 @@ importers: '@masknet/backup-format': link:../backup-format '@masknet/icons': link:../icons '@masknet/plugin-example': link:../plugins/example + '@masknet/plugin-flow': link:../plugins/Flow '@masknet/plugin-infra': link:../plugin-infra '@masknet/plugin-wallet': link:../plugins/Wallet '@masknet/public-api': link:../public-api @@ -262,6 +264,7 @@ importers: '@masknet/icons': workspace:* '@masknet/injected-script': workspace:* '@masknet/plugin-example': workspace:* + '@masknet/plugin-flow': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/plugin-wallet': workspace:* '@masknet/public-api': workspace:* @@ -398,6 +401,7 @@ importers: '@masknet/icons': link:../icons '@masknet/injected-script': link:../injected-script '@masknet/plugin-example': link:../plugins/example + '@masknet/plugin-flow': link:../plugins/Flow '@masknet/plugin-infra': link:../plugin-infra '@masknet/plugin-wallet': link:../plugins/Wallet '@masknet/public-api': link:../public-api @@ -555,6 +559,28 @@ importers: ts-results: 3.3.0 use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + packages/plugins/Flow: + specifiers: + '@masknet/icons': workspace:* + '@masknet/plugin-infra': workspace:* + '@masknet/shared': workspace:* + '@masknet/shared-base': workspace:* + '@masknet/theme': workspace:* + '@masknet/web3-shared-flow': workspace:* + '@onflow/fcl': ^0.0.77 + bignumber.js: ^9.0.1 + react-use: ^17.3.1 + dependencies: + '@masknet/icons': link:../../icons + '@masknet/plugin-infra': link:../../plugin-infra + '@masknet/shared': link:../../shared + '@masknet/shared-base': link:../../shared-base + '@masknet/theme': link:../../theme + '@masknet/web3-shared-flow': link:../../web3-shared/flow + '@onflow/fcl': 0.0.77 + bignumber.js: 9.0.1 + react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + packages/plugins/Wallet: specifiers: '@masknet/plugin-infra': workspace:* @@ -786,6 +812,9 @@ importers: promievent: 0.1.5 web3-eth-contract: 1.5.2 + packages/web3-kit: + specifiers: {} + packages/web3-shared/evm: specifiers: '@dimensiondev/kit': ^0.0.0-20210913111737-84c17d7 @@ -825,6 +854,20 @@ importers: devDependencies: '@types/use-subscription': 1.0.0 + packages/web3-shared/flow: + specifiers: + '@masknet/web3-constants': workspace:* + '@masknet/web3-kit': workspace:* + '@onflow/fcl': ^0.0.77 + '@onflow/types': ^0.0.5 + react-use: ^17.3.1 + dependencies: + '@masknet/web3-constants': link:../../web3-constants + '@masknet/web3-kit': link:../../web3-kit + '@onflow/fcl': 0.0.77 + '@onflow/types': 0.0.5 + react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + packages/web3-shared/solana: specifiers: {} @@ -5569,6 +5612,31 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@improbable-eng/grpc-web-node-http-transport/0.14.1_@improbable-eng+grpc-web@0.14.1: + resolution: {integrity: sha512-ZsCTzI1iKUbmQjB5DNZSI5/hvdliuaPpS2h8mVj1QzynL3IFb5NrNnHVHbfcH1wbm26Ka6Z1CrKFGvKLrmbFIg==} + peerDependencies: + '@improbable-eng/grpc-web': '>=0.13.0' + dependencies: + '@improbable-eng/grpc-web': 0.14.1 + dev: false + + /@improbable-eng/grpc-web/0.12.0_google-protobuf@3.19.1: + resolution: {integrity: sha512-uJjgMPngreRTYPBuo6gswMj1gK39Wbqre/RgE0XnSDXJRg6ST7ZhuS53dFE6Vc2CX4jxgl+cO+0B3op8LA4Q0Q==} + peerDependencies: + google-protobuf: ^3.2.0 + dependencies: + browser-headers: 0.4.1 + google-protobuf: 3.19.1 + dev: false + + /@improbable-eng/grpc-web/0.14.1: + resolution: {integrity: sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw==} + peerDependencies: + google-protobuf: ^3.14.0 + dependencies: + browser-headers: 0.4.1 + dev: false + /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -6214,6 +6282,83 @@ packages: rimraf: 3.0.2 dev: true + /@onflow/fcl/0.0.77: + resolution: {integrity: sha512-hgFW51Va29KwlzhDy6Fm15UesfXluRTR5RJn+zrm5d5HFfkquaxKOnMGT5waKVFn5u4THQIE6v+OnaDDchGNpg==} + dependencies: + '@onflow/interaction': 0.0.11 + '@onflow/rlp': 0.0.3 + '@onflow/sdk': 0.0.54 + '@onflow/types': 0.0.4 + '@onflow/util-actor': 0.0.2 + '@onflow/util-address': 0.0.0 + '@onflow/util-invariant': 0.0.0 + '@onflow/util-template': 0.0.1 + '@onflow/util-uid': 0.0.1 + transitivePeerDependencies: + - google-protobuf + dev: false + + /@onflow/interaction/0.0.11: + resolution: {integrity: sha512-Xuq1Mmx6Wyba/F/L+QLQs0yJeQDsIDwy5SKk5vrCuVgIj0yD8k506g5L8ODrbM1LWll8i0tQsoOi0F85vNl5sA==} + dev: false + + /@onflow/protobuf/0.1.8: + resolution: {integrity: sha512-Taww31RrpJMr3fkWgF2HR2TcRbAoPbMjwRYt9IlYknyRX5YTzpaU35petdqDRfxwmfY9mRxHbiInujX4aV02Hw==} + dependencies: + '@improbable-eng/grpc-web': 0.12.0_google-protobuf@3.19.1 + google-protobuf: 3.19.1 + dev: false + + /@onflow/rlp/0.0.3: + resolution: {integrity: sha512-oAf0VEiMjX8eC6Vd66j1BdGYTHOM6UBaS/sLSScnc7bKX5gICqe2gtEsCeJVE9rUzRk3GD3JqXRnPAW6YFWd/Q==} + dev: false + + /@onflow/sdk/0.0.54: + resolution: {integrity: sha512-4kC1kpxUvWUvWs7kymWX6bJjmch155XmNc3GRT3ZLeCQPIYbEYGVagH9AJzdmBRvxgFiiNpPJaNAjD3NusgCLQ==} + dependencies: + '@improbable-eng/grpc-web': 0.14.1 + '@improbable-eng/grpc-web-node-http-transport': 0.14.1_@improbable-eng+grpc-web@0.14.1 + '@onflow/protobuf': 0.1.8 + '@onflow/rlp': 0.0.3 + '@onflow/util-actor': 0.0.2 + '@onflow/util-address': 0.0.0 + '@onflow/util-invariant': 0.0.0 + '@onflow/util-template': 0.0.1 + deepmerge: 4.2.2 + transitivePeerDependencies: + - google-protobuf + dev: false + + /@onflow/types/0.0.4: + resolution: {integrity: sha512-47r0qTM45mR7FSvyEE0njGljkpgy3MCf/2W82pfZ/PTFGWr1nsGV/4j2bUfK9Sry4Ymz2W20iRZVP3xpqOhqGw==} + dev: false + + /@onflow/types/0.0.5: + resolution: {integrity: sha512-Pgh3hz3Cr8KPpkaDd1E3FdQRASGqpfA1NK7dtgz+6xdTdESeqU2z0ksocrOdfy9ikRvKt4RyFmDuXPx2CVbjuQ==} + dev: false + + /@onflow/util-actor/0.0.2: + resolution: {integrity: sha512-NV3zPXQue3FqVgcIIMo6ifJOiP3hVSQTaR4ZrWLFU5iAZ/L73cTtBMbCB4BUFOe20ALtF2c9PFmpNVowCYV+nw==} + dependencies: + queue-microtask: 1.1.2 + dev: false + + /@onflow/util-address/0.0.0: + resolution: {integrity: sha512-Lzbw/wV3O1fmfXYF2q6iGLgHz/7ATsLXOHceP5tzeEAKNf+srdtTNJv5jhNGhpFFAtQ6TcomXURVMhUg+/4YbA==} + dev: false + + /@onflow/util-invariant/0.0.0: + resolution: {integrity: sha512-ZCt+NqLdeHt9tZhb0DGxo6iSIS9oNUpLkd0PEMzUYUHr4UwrUO7VruV1AUW3PaF9V78DZ13fNZUiQEzdF76O/w==} + dev: false + + /@onflow/util-template/0.0.1: + resolution: {integrity: sha512-qlJ0oq+QujnZRCOGYaw5OKSDpiDIOpwQMYlMe4Mbz//Wn+LOmUghoKZGmRP+YCgp7BJ4aB6AWW/7kL83NDy50A==} + dev: false + + /@onflow/util-uid/0.0.1: + resolution: {integrity: sha512-SzBscBdyn1Zoks0Wo/w7J/Ds9IZ/T+KM/wyWMwWla4PnxwBFviy1BytEQY+sM5q1UNOvaGWgGEoRmH/oOCcglA==} + dev: false + /@openzeppelin/contracts/3.4.1-solc-0.7-2: resolution: {integrity: sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q==} dev: false @@ -11998,6 +12143,10 @@ packages: /brorand/1.1.0: resolution: {integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=} + /browser-headers/0.4.1: + resolution: {integrity: sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==} + dev: false + /browser-process-hrtime/1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} @@ -13778,7 +13927,6 @@ packages: /deepmerge/4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} engines: {node: '>=0.10.0'} - dev: true /default-compare/1.0.0: resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} @@ -16397,6 +16545,10 @@ packages: sparkles: 1.0.1 dev: true + /google-protobuf/3.19.1: + resolution: {integrity: sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==} + dev: false + /got/7.1.0: resolution: {integrity: sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==} engines: {node: '>=4'} @@ -21399,6 +21551,10 @@ packages: deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: true + /queue-microtask/1.1.2: + resolution: {integrity: sha512-F9wwNePtXrzZenAB3ax0Y8TSKGvuB7Qw16J30hspEUTbfUM+H827XyN3rlpwhVmtm5wuZtbKIHjOnwDn7MUxWQ==} + dev: false + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b62cd9690627..84d9aa4e9f4f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,9 +12,11 @@ packages: - 'packages/public-api' - 'packages/shared-base' - 'packages/shared' + - 'packages/web3-kit' - 'packages/web3-constants' - 'packages/web3-contracts' - 'packages/web3-shared/evm' + - 'packages/web3-shared/flow' - 'packages/web3-shared/solana' - 'packages/storybook-shared' - 'packages/icons' @@ -22,5 +24,6 @@ packages: - 'packages/plugin-infra' - 'packages/plugins/example' - 'packages/plugins/Wallet' + - 'packages/plugins/Flow' - 'packages/external-plugin-previewer' - 'packages/backup-format' From e717a23cebff67f7b2a27983e2fe85319ea36510 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 4 Nov 2021 22:38:19 +0800 Subject: [PATCH 02/41] refactor: select provider dialog --- .../src/initialization/Dashboard.tsx | 7 +- .../InjectedComponents/PageInspector.tsx | 5 +- .../src/plugins/EVM/UI/Dashboard/index.tsx | 10 +- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 10 +- .../plugins/EVM/UI/components/PluginIcon.tsx | 16 -- .../plugins/EVM/UI/components/PluginPanel.tsx | 20 --- .../mask/src/plugins/EVM/assets/arbitrum.png | Bin 0 -> 35907 bytes .../mask/src/plugins/EVM/assets/binance.png | Bin 0 -> 3471 bytes .../src/plugins/EVM/assets/masknetwork.png | Bin 0 -> 18209 bytes .../mask/src/plugins/EVM/assets/metamask.png | Bin 0 -> 16442 bytes .../mask/src/plugins/EVM/assets/polygon.png | Bin 0 -> 1841 bytes .../src/plugins/EVM/assets/walletconnect.png | Bin 0 -> 177386 bytes packages/mask/src/plugins/EVM/assets/xdai.png | Bin 0 -> 3409 bytes packages/mask/src/plugins/EVM/base.ts | 4 +- packages/mask/src/plugins/EVM/constants.ts | 54 ++++++ .../SelectProviderDialog/NetworkIcon.tsx | 21 +++ .../PluginProviderRender.tsx | 158 ++++++++++++++++-- .../SelectProviderDialog/ProviderIcon.tsx | 53 ++++++ .../SelectProviderDialog/ProviderTab.tsx | 43 ----- .../SelectProviderDialog/ProviderTabPanel.tsx | 21 --- .../SNSAdaptor/SelectProviderDialog/index.tsx | 4 +- packages/mask/src/tsconfig.json | 4 +- packages/mask/src/web3/UI/DateTimePanel.tsx | 2 +- .../mask/src/web3/{UI => assets}/calendar.png | Bin packages/plugin-infra/src/index.ts | 9 +- packages/plugin-infra/src/manager/store.ts | 31 +++- packages/plugin-infra/src/types.ts | 45 ++++- .../plugins/Flow/src/UI/Dashboard/index.tsx | 10 +- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 8 +- packages/plugins/Flow/src/assets/blocto.png | Bin 0 -> 11445 bytes packages/plugins/Flow/src/base.ts | 4 +- packages/plugins/Flow/src/constants.ts | 18 ++ .../components/SelectProviderDialog/index.tsx | 54 ++++++ packages/shared/tsconfig.json | 2 +- packages/web3-shared/flow/types.ts | 4 + 35 files changed, 462 insertions(+), 155 deletions(-) delete mode 100644 packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx create mode 100644 packages/mask/src/plugins/EVM/assets/arbitrum.png create mode 100644 packages/mask/src/plugins/EVM/assets/binance.png create mode 100644 packages/mask/src/plugins/EVM/assets/masknetwork.png create mode 100644 packages/mask/src/plugins/EVM/assets/metamask.png create mode 100644 packages/mask/src/plugins/EVM/assets/polygon.png create mode 100644 packages/mask/src/plugins/EVM/assets/walletconnect.png create mode 100644 packages/mask/src/plugins/EVM/assets/xdai.png create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx delete mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx delete mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx rename packages/mask/src/web3/{UI => assets}/calendar.png (100%) create mode 100644 packages/plugins/Flow/src/assets/blocto.png create mode 100644 packages/shared/src/UI/components/SelectProviderDialog/index.tsx diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index b62e3fad2001..e7ed39a441c6 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -9,18 +9,19 @@ import { NoEffectUsePortalShadowRootContext, } from '@masknet/theme' import { ErrorBoundary } from '@masknet/shared' +import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' +import { Web3Provider } from '@masknet/web3-shared-evm' import i18n from 'i18next' import { I18nextProvider } from 'react-i18next' import './PluginHost' -import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' import { Pages } from '../pages/routes' -import { useAppearance } from '../pages/Personas/api' -import { Web3Provider } from '@masknet/web3-shared-evm' import { Web3Context } from '../web3/context' +import { useAppearance } from '../pages/Personas/api' import { PersonaContext } from '../pages/Personas/hooks/usePersonaContext' + const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) => x.GlobalInjection) export default function DashboardRoot() { diff --git a/packages/mask/src/components/InjectedComponents/PageInspector.tsx b/packages/mask/src/components/InjectedComponents/PageInspector.tsx index 9039186289c6..1606eb643a8e 100644 --- a/packages/mask/src/components/InjectedComponents/PageInspector.tsx +++ b/packages/mask/src/components/InjectedComponents/PageInspector.tsx @@ -6,12 +6,15 @@ import { useMatchXS, MaskMessages, useI18N } from '../../utils' import { useAutoPasteFailedDialog } from './AutoPasteFailedDialog' const PluginRender = createInjectHooksRenderer(useActivatedPluginsSNSAdaptor, (x) => x.GlobalInjection) + export interface PageInspectorProps {} + export function PageInspector(props: PageInspectorProps) { - const { showSnackbar, closeSnackbar } = useCustomSnackbar() const { t } = useI18N() + const { showSnackbar, closeSnackbar } = useCustomSnackbar() const [autoPasteFailed, JSX] = useAutoPasteFailedDialog() const xsMatched = useMatchXS() + useEffect( () => MaskMessages.events.autoPasteFailed.on((data) => { diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index 48bada595505..2da7b6b25d2b 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,15 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { PluginIcon } from '../components/PluginIcon' -import { PluginPanel } from '../components/PluginPanel' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectProviderDialogEntry: { - name: 'EVM', - icon: , - panel: , + SelectNetworkDialogEntry: { + async onSelect(network, provider) { + console.log(`EVM DASHBOARD: ${network.ID} ${provider.ID}`) + }, }, } diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index 48bada595505..53145092108e 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,15 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { PluginIcon } from '../components/PluginIcon' -import { PluginPanel } from '../components/PluginPanel' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectProviderDialogEntry: { - name: 'EVM', - icon: , - panel: , + SelectNetworkDialogEntry: { + async onSelect(network, provider) { + console.log(`EVM: ${network.ID} ${provider.ID}`) + }, }, } diff --git a/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx b/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx deleted file mode 100644 index 900f3cdc3935..000000000000 --- a/packages/mask/src/plugins/EVM/UI/components/PluginIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { makeStyles } from '@masknet/theme' - -const useStyles = makeStyles()({ - image: { - width: 24, - height: 24, - }, -}) - -export interface PluginIconProps {} - -export function PluginIcon(props: PluginIconProps) { - const { classes } = useStyles() - const iconURL = new URL('../../assets/ethereum.png', import.meta.url).toString() - return -} diff --git a/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx b/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx index 5680b79afcba..9e9a945a001a 100644 --- a/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx +++ b/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx @@ -96,26 +96,12 @@ export function PluginPanel(props: PluginPanelProps) { const { t } = useI18N() const classes = useStylesExtends(useStyles(), props) - const account = useAccount() const chainId = useChainId() - const history = useHistory() //#region remote controlled dialog logic const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) //#endregion - //#region wallet status dialog - const { openDialog: openWalletStatusDialog } = useRemoteControlledDialog( - WalletMessages.events.walletStatusDialogUpdated, - ) - //#endregion - - //#region select wallet dialog - const { setDialog: setSelectWalletDialog } = useRemoteControlledDialog( - WalletMessages.events.selectWalletDialogUpdated, - ) - //#endregion - //#region connect wallet dialog const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( WalletMessages.events.connectWalletDialogUpdated, @@ -130,7 +116,6 @@ export function PluginPanel(props: PluginPanelProps) { const wallets = useWallets(ProviderType.MaskWallet) const selectedNetworkType = useValueRef(currentNetworkSettings) - const selectedProviderType = useValueRef(currentProviderSettings) //#region undetermined network type const [undeterminedNetworkType, setUndeterminedNetworkType] = useState(selectedNetworkType) @@ -167,15 +152,10 @@ export function PluginPanel(props: PluginPanelProps) { } }, [ - account, chainId, wallets, - history, closeDialog, undeterminedNetworkType, - selectedProviderType, - openWalletStatusDialog, - setSelectWalletDialog, setWalletConnectDialog, ], ) diff --git a/packages/mask/src/plugins/EVM/assets/arbitrum.png b/packages/mask/src/plugins/EVM/assets/arbitrum.png new file mode 100644 index 0000000000000000000000000000000000000000..9acea4e36db9e5b8c9c6da9693fc5fa41dedfaf9 GIT binary patch literal 35907 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 literal 0 HcmV?d00001 diff --git a/packages/mask/src/plugins/EVM/assets/masknetwork.png b/packages/mask/src/plugins/EVM/assets/masknetwork.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd7f5e7e2b8b1a9aa21d52768b5aac6ea0e9af7 GIT binary patch literal 18209 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 e`dY?!vcdw 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
    _3!-CD^poH+>4&^#`%I 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 literal 0 HcmV?d00001 diff --git a/packages/mask/src/plugins/EVM/base.ts b/packages/mask/src/plugins/EVM/base.ts index 07d100412494..3a6031de0aa9 100644 --- a/packages/mask/src/plugins/EVM/base.ts +++ b/packages/mask/src/plugins/EVM/base.ts @@ -1,5 +1,5 @@ import type { Plugin } from '@masknet/plugin-infra' -import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION } from './constants' +import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION, PLUGIN_PROVIDERS, PLUGIN_NETWORKS } from './constants' export const base: Plugin.Shared.Definition = { ID: PLUGIN_ID, @@ -12,4 +12,6 @@ export const base: Plugin.Shared.Definition = { networks: { type: 'opt-out', networks: {} }, target: 'stable', }, + networks: PLUGIN_NETWORKS, + providers: PLUGIN_PROVIDERS, } diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts index a462fe41914d..01ea675e8f21 100644 --- a/packages/mask/src/plugins/EVM/constants.ts +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -1,5 +1,59 @@ +import { NetworkType, ProviderType } from "@masknet/web3-shared-evm" + export const PLUGIN_META_KEY = 'com.maskbook.evm' export const PLUGIN_ID = 'com.maskbook.evm' export const PLUGIN_NAME = 'EVM' export const PLUGIN_ICON = 'Ξ' export const PLUGIN_DESCRIPTION = '' +export const PLUGIN_NETWORKS = [ + { + ID: `${PLUGIN_ID}_ethereum`, + type: NetworkType.Ethereum, + name: 'Ethereum', + icon: new URL('./assets/ethereum.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_bsc`, + type: NetworkType.Binance, + name: 'BSC', + icon: new URL('./assets/binance.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_polygon`, + type: NetworkType.Polygon, + name: 'Polygon', + icon: new URL('./assets/polygon.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_arbitrum`, + type: NetworkType.Arbitrum, + name: 'Arbitrum One', + icon: new URL('./assets/arbitrum.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_xdai`, + type: NetworkType.xDai, + name: 'xDai', + icon: new URL('./assets/xdai.png', import.meta.url).toString(), + }, +] +export const PLUGIN_PROVIDERS = [ + { + ID: `${PLUGIN_ID}_maskwallet`, + type: ProviderType.MaskWallet, + name: 'Mask Network', + icon: new URL('./assets/maskwallet.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_metamask`, + type: ProviderType.MetaMask, + name: 'MetaMask', + icon: new URL('./assets/metamask.png', import.meta.url).toString(), + }, + { + ID: `${PLUGIN_ID}_walletconnect`, + type: ProviderType.WalletConnect, + name: 'WalletConnect', + icon: new URL('./assets/walletconnect.png', import.meta.url).toString(), + }, +] diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx new file mode 100644 index 000000000000..9473a86c5e32 --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx @@ -0,0 +1,21 @@ +import { makeStyles } from '@masknet/theme' + +const useStyles = makeStyles()((theme) => { + return { + icon: { + width: '100%', + height: '100%', + borderRadius: '50%', + backgroundColor: theme.palette.background.paper, + }, + } +}) + +export interface NetworkIconProps { + size?: number + icon: string +} +export function NetworkIcon({ size = 48, icon }: NetworkIconProps) { + const { classes } = useStyles() + return +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index 777f33546ccb..6ff3c2a51473 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -1,18 +1,150 @@ -import { useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor } from '@masknet/plugin-infra' -import { PLUGIN_ID as EVM_PLUGIN_ID } from '../../../EVM/constants' -import { ProviderTab } from './ProviderTab' +import { useMemo, useState } from 'react' +import { SuccessIcon } from '@masknet/icons' +import { getMaskColor, makeStyles } from '@masknet/theme' +import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' +import { + useRegisteredProviders, + useRegisteredNetworks, + useActivatedPluginsSNSAdaptor, + useActivatedPluginsDashboard, + Plugin, +} from '@masknet/plugin-infra' +import { ProviderIcon } from './ProviderIcon' +import { NetworkIcon } from './NetworkIcon' + +const useStyles = makeStyles()((theme) => ({ + root: { + display: 'flex', + flexDirection: 'column', + padding: theme.spacing(2, 4), + }, + section: { + flexGrow: 1, + marginTop: 21, + '&:first-child': { + marginTop: 0, + }, + }, + title: { + fontSize: 19, + fontWeight: 'bold', + }, + list: { + marginTop: 21, + display: 'flex', + gap: 32, + }, + networkItem: { + width: 'auto', + padding: 0, + }, + iconWrapper: { + position: 'relative', + cursor: 'pointer', + width: 48, + height: 48, + borderRadius: '50%', + backgroundColor: getMaskColor(theme).twitterBackground, + }, + networkIcon: { + backgroundColor: getMaskColor(theme).twitterBackground, + }, + checkedBadge: { + position: 'absolute', + right: 0, + bottom: 0, + width: 14, + height: 14, + background: '#fff', + borderRadius: '50%', + }, + alert: { + fontSize: 12, + display: 'flex', + alignItems: 'center', + marginTop: theme.spacing(1), + }, + grid: { + width: '100%', + margin: theme.spacing(2, 0, 0), + }, + providerIcon: { + fontSize: 45, + }, +})) export interface PluginProviderRenderProps {} -export const PluginProviderRender = function (props: PluginProviderRenderProps) { - const tabs = [...useActivatedPluginsSNSAdaptor(), ...useActivatedPluginsDashboard()] - .sort((a, b) => { - if (a.ID === EVM_PLUGIN_ID) return -1 - if (b.ID === EVM_PLUGIN_ID) return 1 - return 1 - }) - .map((plugin) => plugin.SelectProviderDialogEntry!) - .filter(Boolean) +export function PluginProviderRender(props: PluginProviderRenderProps) { + const { classes } = useStyles() + + const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() + const pluginsDashboard = useActivatedPluginsDashboard() + const networks = useRegisteredNetworks() + const providers = useRegisteredProviders() + const [undeterminedPluginID, setUndeterminedPluginID] = useState('') + const [undeterminedNetworkID, setUndeterminedNetworkID] = useState('') + + const onSwtich = useMemo(() => { + return (network?: Plugin.Shared.Network, provider?: Plugin.Shared.Provider) => { + if (!network || !provider) return + pluginsSNSAdaptor + .find((x) => x.ID === undeterminedPluginID) + ?.SelectNetworkDialogEntry?.onSelect(network, provider) + pluginsDashboard + .find((x) => x.ID === undeterminedPluginID) + ?.SelectNetworkDialogEntry?.onSelect(network, provider) + } + }, [undeterminedPluginID, pluginsSNSAdaptor, pluginsDashboard]) - return + return ( + +
    + + 1. Choose Network + + + {networks?.map((network) => ( + { + setUndeterminedPluginID(network.pluginID) + setUndeterminedNetworkID(network.ID) + }}> +
    + + {undeterminedNetworkID === network.ID && ( + + )} +
    +
    + ))} +
    +
    +
    + + 2. Choose Wallet + + + {providers + .filter((x) => x.pluginID === undeterminedPluginID) + .map((provider) => ( + + + onSwtich( + networks.find((x) => x.ID === undeterminedNetworkID), + provider, + ) + } + /> + + ))} + +
    +
    + ) } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx new file mode 100644 index 000000000000..b3d3a58951ee --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx @@ -0,0 +1,53 @@ +import { makeStyles } from '@masknet/theme' +import { getMaskColor } from '@masknet/theme' +import { Typography, Card, ButtonBase, ButtonBaseProps } from '@mui/material' + +const useStyles = makeStyles()((theme) => ({ + root: { + textAlign: 'center', + }, + content: { + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: theme.spacing(4, 1), + backgroundColor: getMaskColor(theme).twitterBackground, + }, + icon: { + width: 45, + height: 45, + marginBottom: theme.spacing(2), + }, + name: { + fontSize: 16, + fontWeight: 'normal', + whiteSpace: 'nowrap', + marginBottom: theme.spacing(1), + }, + description: { + fontSize: 14, + fontWeight: 300, + }, +})) + +export interface ProviderIconProps { + icon: string + name: React.ReactNode + onClick?: () => void + ButtonBaseProps?: Partial +} +export function ProviderIcon({ icon, name, onClick, ButtonBaseProps }: ProviderIconProps) { + const { classes } = useStyles() + return ( + + + + + {name} + + + + ) +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx deleted file mode 100644 index 751a4324d93f..000000000000 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTab.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useState, ReactNode } from 'react' -import { Box, Tab, Tabs } from '@mui/material' -import { makeStyles } from '@masknet/theme' -import { ProviderTabPanel } from './ProviderTabPanel' - -const useStyles = makeStyles()((theme) => ({ - root: {}, - tabs: { - width: 80, - }, - tab: { - maxWidth: '100%', - minWidth: 0, - }, -})) - -export interface ProviderTabProps { - tabs: { - name: ReactNode - icon: ReactNode - panel: ReactNode - }[] -} - -export function ProviderTab(props: ProviderTabProps) { - const { classes } = useStyles() - const [value, setValue] = useState(0) - return ( - - setValue(newValue)}> - {props.tabs.map((x, i) => ( - - ))} - - {props.tabs.map((x, i) => (value === i ? {x.panel} : null))} - - ) -} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx deleted file mode 100644 index 6386d56c6259..000000000000 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderTabPanel.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { ReactNode } from 'react' -import { Box } from '@mui/material' -import { makeStyles } from '@masknet/theme' - -const useStyles = makeStyles()((theme) => ({ - root: { - flex: 1, - minHeight: 300, - padding: theme.spacing(2), - overflow: 'auto', - }, -})) - -export interface ProviderTabPanelProps { - children: ReactNode -} - -export function ProviderTabPanel(props: ProviderTabPanelProps) { - const { classes } = useStyles() - return {props.children} -} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index ea53e7ecf0dc..59c5eb8dfe6e 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,12 +1,12 @@ import { useEffect } from 'react' import { makeStyles } from '@masknet/theme' import { DialogContent } from '@mui/material' -import { useRemoteControlledDialog, useStylesExtends } from '@masknet/shared' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' +import { useRemoteControlledDialog } from '@masknet/shared' const useStyles = makeStyles()((theme) => ({ content: { @@ -22,7 +22,7 @@ interface SelectProviderDialogUIProps extends withClasses {} function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { const { t } = useI18N() - const classes = useStylesExtends(useStyles(), props) + const classes = useStyles() //#region remote controlled dialog logic const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) diff --git a/packages/mask/src/tsconfig.json b/packages/mask/src/tsconfig.json index 61513f22e4a1..5c9197dadf74 100644 --- a/packages/mask/src/tsconfig.json +++ b/packages/mask/src/tsconfig.json @@ -7,7 +7,7 @@ "emitDeclarationOnly": true, "lib": ["ES2021"] }, - "include": ["./", "./**/*.json"], + "include": ["./", "./**/*.json", "plugins/Wallet/SNSAdaptor/SelectProviderDialog"], // ! Note: mask/ depends dashboard/ on source-code level // ! but dashboard/ depends mask/ on type level // ! do not add dashboard/ as a reference otherwise there is a circular dependency on the type level. @@ -16,10 +16,12 @@ { "path": "../../shared" }, { "path": "../../shared-base" }, { "path": "../../web3-shared/evm" }, + { "path": "../../web3-shared/flow" }, { "path": "../../theme" }, { "path": "../../icons" }, { "path": "../../plugin-infra" }, { "path": "../../plugins/Wallet" }, + { "path": "../../plugins/Flow" }, { "path": "../../external-plugin-previewer" }, { "path": "../../injected-script/sdk" }, { "path": "../../mask-sdk/server" }, diff --git a/packages/mask/src/web3/UI/DateTimePanel.tsx b/packages/mask/src/web3/UI/DateTimePanel.tsx index c4594c99f46f..a9b28eaad5dc 100644 --- a/packages/mask/src/web3/UI/DateTimePanel.tsx +++ b/packages/mask/src/web3/UI/DateTimePanel.tsx @@ -13,7 +13,7 @@ const useStyles = makeStyles()({ datetime: { '&::-webkit-calendar-picker-indicator': { marginLeft: 0, - backgroundImage: `url(${new URL('./calendar.png', import.meta.url)})`, + backgroundImage: `url(${new URL('../assets/calendar.png', import.meta.url)})`, }, }, inputLabel: { diff --git a/packages/mask/src/web3/UI/calendar.png b/packages/mask/src/web3/assets/calendar.png similarity index 100% rename from packages/mask/src/web3/UI/calendar.png rename to packages/mask/src/web3/assets/calendar.png diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 4eca07c25185..c66ebffb5cda 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -5,5 +5,12 @@ export * from './manager/worker' export * from './utils' export * from './PostContext' export * from 'ts-results' -export { registerPlugin, registeredPlugins, registeredPluginIDs, useRegisteredPlugins } from './manager/store' +export { + registerPlugin, + registeredPlugins, + registeredPluginIDs, + useRegisteredPlugins, + useRegisteredNetworks, + useRegisteredProviders, +} from './manager/store' export { activatedPluginsWorker } from './manager/worker' diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index 778677226df5..fb2b0910c0f4 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -1,3 +1,4 @@ +import { useMemo } from 'react' import type { Plugin } from '../types' const __registered = new Map() @@ -14,7 +15,35 @@ export function registerPlugin(def: Plugin.DeferredDefinition) { } export function useRegisteredPlugins() { - return [...__registered.values()] + return [...__registered.values()].sort((a, b) => { + if (a.ID.includes('evm')) return -1 + if (b.ID.includes('evm')) return 1 + return 0 + }) +} + +export function useRegisteredNetworks() { + const plugins = useRegisteredPlugins() + return useMemo(() => { + return plugins.flatMap((x) => + (x.networks ?? []).map((y) => ({ + ...y, + pluginID: x.ID, + })), + ) + }, [plugins.map((x) => x.ID).join()]) +} + +export function useRegisteredProviders() { + const plugins = useRegisteredPlugins() + return useMemo(() => { + return plugins.flatMap((x) => + (x.providers ?? []).map((y) => ({ + ...y, + pluginID: x.ID, + })), + ) + }, [plugins.map((x) => x.ID).join()]) } function __meetRegisterRequirement(def: Plugin.Shared.Definition) { diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 5c684771a971..fb96d034f971 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -1,7 +1,7 @@ import type React from 'react' import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' -import type { ChainId } from '@masknet/web3-shared-evm' +import type { ChainId, Web3ProviderType } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' export namespace Plugin { @@ -96,6 +96,10 @@ export namespace Plugin.Shared { management?: ManagementProperty /** i18n resources of this plugin */ i18n?: I18NResource + /** Introduce networks information. */ + networks?: Network[] + /** Introduce wallet providers information. */ + providers?: Provider[] } /** * This part is shared between Dashboard, SNSAdaptor and Worker part @@ -167,6 +171,28 @@ export namespace Plugin.Shared { export type I18NKey = string export type I18NValue = string export type I18NResource = Record> + + export interface Network { + /** An unique ID for each network */ + ID: string + /** The network type */ + type: string + /** The network icon */ + icon: string + /** The network name */ + name: string + } + + export interface Provider { + /** An unique ID for each wallet provider */ + ID: string + /** The provider type */ + type: string + /** The provider icon */ + icon: string + /** The provider name */ + name: string + } } /** This part runs in the SNSAdaptor */ @@ -183,7 +209,7 @@ export namespace Plugin.SNSAdaptor { /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be an entry of network in the Select Provider Dialog. */ - SelectProviderDialogEntry?: SelectProviderDialogEntry + SelectNetworkDialogEntry?: SelectNetworkDialogEntry /** This UI will be use when there is known badges. */ CompositionDialogMetadataBadgeRender?: CompositionMetadataBadgeRender /** This UI will be rendered as an entry in the toolbar (if the SNS has a Toolbar support) */ @@ -223,10 +249,15 @@ export namespace Plugin.SNSAdaptor { keepMounted?: boolean } - export interface SelectProviderDialogEntry { - name: React.ReactNode - icon: React.ReactNode - panel: React.ReactNode + export interface SelectNetworkDialogEntry { + /** + * This function will be called when the user chooses a new network with a specific wallet provider. + * The plugin must provide a data persistence solution. And that data should only alter in this callback. + * The infra will take its duty to track which network is used at the current stage. + * @param network + * @param provider + */ + onSelect(network: Shared.Network, provider: Shared.Provider): Promise } export interface CompositionDialogEntry_DialogProps { open: boolean @@ -279,7 +310,7 @@ export namespace Plugin.Dashboard { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> /** This UI will be an entry of network in the Select Provider Dialog. */ - SelectProviderDialogEntry?: Plugin.SNSAdaptor.SelectProviderDialogEntry + SelectNetworkDialogEntry?: Plugin.SNSAdaptor.SelectNetworkDialogEntry } } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index d4ce558cd055..a1ee6f37ce1f 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,15 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { PluginIcon } from '../components/PluginIcon' -import { PluginPanel } from '../components/PluginPanel' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectProviderDialogEntry: { - name: 'Flow', - icon: , - panel: , + SelectNetworkDialogEntry: { + async onSelect(network, provider) { + console.log(`FLOW DASHBOARD: ${network.ID} ${provider.ID}`) + }, }, } diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index d4ce558cd055..eba1b731b21f 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -6,10 +6,10 @@ import { PluginPanel } from '../components/PluginPanel' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectProviderDialogEntry: { - name: 'Flow', - icon: , - panel: , + SelectNetworkDialogEntry: { + async onSelect(network, provider) { + console.log(`FLOW: ${network.ID} ${provider.ID}`) + }, }, } diff --git a/packages/plugins/Flow/src/assets/blocto.png b/packages/plugins/Flow/src/assets/blocto.png new file mode 100644 index 0000000000000000000000000000000000000000..efbec079be35c4b4db849ed08d834f8b6b3395db GIT binary patch literal 11445 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 SGC!z82B(eA8J3=OjQ9`vEbSHm literal 0 HcmV?d00001 diff --git a/packages/plugins/Flow/src/base.ts b/packages/plugins/Flow/src/base.ts index 60560f345a8c..858a80402717 100644 --- a/packages/plugins/Flow/src/base.ts +++ b/packages/plugins/Flow/src/base.ts @@ -1,6 +1,6 @@ import type { Plugin } from '@masknet/plugin-infra' import { languages } from './locales' -import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION } from './constants' +import { PLUGIN_ID, PLUGIN_ICON, PLUGIN_NAME, PLUGIN_DESCRIPTION, PLUGIN_PROVIDERS, PLUGIN_NETWORKS } from './constants' export const base: Plugin.Shared.Definition = { ID: PLUGIN_ID, @@ -14,4 +14,6 @@ export const base: Plugin.Shared.Definition = { target: 'stable', }, i18n: languages, + networks: PLUGIN_NETWORKS, + providers: PLUGIN_PROVIDERS, } diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts index fa43fbed6e35..8573d031a2c3 100644 --- a/packages/plugins/Flow/src/constants.ts +++ b/packages/plugins/Flow/src/constants.ts @@ -1,5 +1,23 @@ +import { NetworkType, ProviderType} from '@masknet/web3-shared-flow' + export const PLUGIN_META_KEY = 'com.maskbook.flow' export const PLUGIN_ID = 'com.maskbook.flow' export const PLUGIN_NAME = 'Flow Chain' export const PLUGIN_ICON = 'F' export const PLUGIN_DESCRIPTION = '' +export const PLUGIN_NETWORKS = [ + { + ID: `${PLUGIN_ID}_flow`, + type: NetworkType.Flow, + name: 'Flow', + icon: new URL('./assets/flow.png', import.meta.url).toString(), + }, +] +export const PLUGIN_PROVIDERS = [ + { + ID: `${PLUGIN_ID}_blocto`, + type: ProviderType.Blocto, + name: 'Blocto', + icon: new URL('./assets/blocto.png', import.meta.url).toString(), + }, +] diff --git a/packages/shared/src/UI/components/SelectProviderDialog/index.tsx b/packages/shared/src/UI/components/SelectProviderDialog/index.tsx new file mode 100644 index 000000000000..59c5eb8dfe6e --- /dev/null +++ b/packages/shared/src/UI/components/SelectProviderDialog/index.tsx @@ -0,0 +1,54 @@ +import { useEffect } from 'react' +import { makeStyles } from '@masknet/theme' +import { DialogContent } from '@mui/material' +import { useI18N } from '../../../../utils/i18n-next-ui' +import { WalletMessages } from '../../messages' +import { InjectedDialog } from '../../../../components/shared/InjectedDialog' +import { hasNativeAPI, nativeAPI } from '../../../../utils' +import { PluginProviderRender } from './PluginProviderRender' +import { useRemoteControlledDialog } from '@masknet/shared' + +const useStyles = makeStyles()((theme) => ({ + content: { + padding: theme.spacing(0), + scrollbarWidth: 'none', + '&::-webkit-scrollbar': { + display: 'none', + }, + }, +})) + +interface SelectProviderDialogUIProps extends withClasses {} + +function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { + const { t } = useI18N() + const classes = useStyles() + + //#region remote controlled dialog logic + const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) + //#endregion + + //#region native app + useEffect(() => { + if (!open) return + if (hasNativeAPI) nativeAPI?.api.misc_openCreateWalletView() + }, [open]) + //#endregion + + // not available for the native app + if (hasNativeAPI) return null + + return ( + + + + + + ) +} + +export interface SelectProviderDialogProps extends SelectProviderDialogUIProps {} + +export function SelectProviderDialog(props: SelectProviderDialogProps) { + return +} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 9c37d1905d8c..f81e2f93aa40 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "./dist/", "tsBuildInfoFile": "./dist/.tsbuildinfo" }, - "include": ["./src", "./src/**/*.json"], + "include": ["./src", "./src/**/*.json", "../mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog"], "references": [ { "path": "../web3-shared/evm" }, { "path": "../theme" }, diff --git a/packages/web3-shared/flow/types.ts b/packages/web3-shared/flow/types.ts index 166499366a34..d582eaa4a99a 100644 --- a/packages/web3-shared/flow/types.ts +++ b/packages/web3-shared/flow/types.ts @@ -3,6 +3,10 @@ export enum ChainId { Testnet = 2, } +export enum NetworkType { + Flow = 'Flow', +} + export enum ProviderType { Blocto = 'Blocto', Dapper = 'Dapper', From 17ed74c8c7c88beb17bc5ee5b97e654060db3eb3 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Fri, 5 Nov 2021 02:22:11 +0800 Subject: [PATCH 03/41] refactor: select provider dialog --- .../src/initialization/Dashboard.tsx | 1 - .../src/plugins/EVM/UI/Dashboard/index.tsx | 7 +- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 7 +- .../plugins/EVM/UI/components/PluginPanel.tsx | 219 ------------------ .../plugins/EVM/UI/components/Provider.tsx | 62 ----- .../UI/components/ProviderIconClickBait.tsx | 61 +++++ .../{masknetwork.png => maskwallet.png} | Bin packages/mask/src/plugins/EVM/constants.ts | 2 +- .../PluginProviderRender.tsx | 69 +++--- .../SNSAdaptor/SelectProviderDialog/index.tsx | 4 +- packages/mask/src/settings/settings.ts | 10 + packages/mask/src/tsconfig.json | 2 +- packages/plugin-infra/README.md | 2 +- packages/plugin-infra/src/manager/manage.ts | 6 +- packages/plugin-infra/src/manager/store.ts | 2 + packages/plugin-infra/src/types.ts | 31 +-- packages/plugins/Flow/package.json | 3 +- .../plugins/Flow/src/UI/Dashboard/index.tsx | 11 +- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 9 +- .../Flow/src/UI/components/NetworkIcon.tsx | 12 - .../Flow/src/UI/components/PluginIcon.tsx | 16 -- .../Flow/src/UI/components/ProviderIcon.tsx | 11 - .../UI/components/ProviderIconClickBait.tsx | 33 +++ packages/plugins/Flow/src/constants.ts | 2 +- packages/plugins/Flow/tsconfig.json | 9 +- packages/plugins/Wallet/tsconfig.json | 8 +- .../components/SelectProviderDialog/index.tsx | 54 ----- packages/shared/tsconfig.json | 2 +- packages/web3-kit/src/index.ts | 1 + packages/web3-shared/flow/index.ts | 2 +- pnpm-lock.yaml | 2 - 31 files changed, 193 insertions(+), 467 deletions(-) delete mode 100644 packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx delete mode 100644 packages/mask/src/plugins/EVM/UI/components/Provider.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx rename packages/mask/src/plugins/EVM/assets/{masknetwork.png => maskwallet.png} (100%) delete mode 100644 packages/plugins/Flow/src/UI/components/NetworkIcon.tsx delete mode 100644 packages/plugins/Flow/src/UI/components/PluginIcon.tsx delete mode 100644 packages/plugins/Flow/src/UI/components/ProviderIcon.tsx create mode 100644 packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx delete mode 100644 packages/shared/src/UI/components/SelectProviderDialog/index.tsx diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index e7ed39a441c6..6e26a948cda3 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -21,7 +21,6 @@ import { Web3Context } from '../web3/context' import { useAppearance } from '../pages/Personas/api' import { PersonaContext } from '../pages/Personas/hooks/usePersonaContext' - const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) => x.GlobalInjection) export default function DashboardRoot() { diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index 2da7b6b25d2b..9e442d4fd95d 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,14 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectNetworkDialogEntry: { - async onSelect(network, provider) { - console.log(`EVM DASHBOARD: ${network.ID} ${provider.ID}`) - }, - }, + ProviderIconClickBait, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index 53145092108e..9e442d4fd95d 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,14 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectNetworkDialogEntry: { - async onSelect(network, provider) { - console.log(`EVM: ${network.ID} ${provider.ID}`) - }, - }, + ProviderIconClickBait, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx b/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx deleted file mode 100644 index 9e9a945a001a..000000000000 --- a/packages/mask/src/plugins/EVM/UI/components/PluginPanel.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' -import { useAsync } from 'react-use' -import { getMaskColor, makeStyles } from '@masknet/theme' -import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' -import { getChainIdFromNetworkType, ProviderType, useAccount, useChainId, useWallets } from '@masknet/web3-shared-evm' -import { useValueRef, useRemoteControlledDialog, useStylesExtends, NetworkIcon } from '@masknet/shared' -import { unreachable } from '@dimensiondev/kit' -import { SuccessIcon } from '@masknet/icons' -import { PopupRoutes } from '@masknet/shared-base' -import { WalletMessages } from '@masknet/plugin-wallet' -import { useHistory } from 'react-router-dom' -import classnames from 'classnames' -import { Flags, useI18N } from '../../../../utils' -import Services from '../../../../extension/service' -import { currentNetworkSettings, currentProviderSettings } from '../../../Wallet/settings' -import { WalletRPC } from '../../../Wallet/messages' -import { MaskIcon } from '../../../../resources/MaskIcon' -import { MetaMaskIcon } from '../../../../resources/MetaMaskIcon' -import { WalletConnectIcon } from '../../../../resources/WalletConnectIcon' -import { Provider } from './Provider' - -const useStyles = makeStyles()((theme) => ({ - paper: { - width: '750px !important', - maxWidth: 'unset', - }, - content: { - padding: theme.spacing(0), - }, - step: { - flexGrow: 1, - marginTop: 21, - '&:first-child': { - marginTop: 0, - }, - }, - stepTitle: { - fontSize: 19, - fontWeight: 'bold', - }, - stepContent: { - marginTop: 21, - }, - networkDisabled: { - opacity: 0.5, - }, - networkList: { - display: 'flex', - gap: 32, - }, - networkItem: { - width: 'auto', - padding: 0, - }, - iconWrapper: { - position: 'relative', - cursor: 'pointer', - height: 48, - width: 48, - borderRadius: 48, - backgroundColor: getMaskColor(theme).twitterBackground, - }, - networkIcon: { - backgroundColor: getMaskColor(theme).twitterBackground, - }, - checkedBadge: { - position: 'absolute', - right: 0, - bottom: 0, - width: 14, - height: 14, - background: '#fff', - borderRadius: '50%', - }, - alert: { - fontSize: 12, - display: 'flex', - alignItems: 'center', - marginTop: theme.spacing(1), - }, - grid: { - width: '100%', - margin: theme.spacing(2, 0, 0), - }, - providerIcon: { - fontSize: 45, - }, - tip: { - fontSize: 12, - }, -})) - -export interface PluginPanelProps {} - -export function PluginPanel(props: PluginPanelProps) { - const { t } = useI18N() - const classes = useStylesExtends(useStyles(), props) - - const chainId = useChainId() - - //#region remote controlled dialog logic - const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) - //#endregion - - //#region connect wallet dialog - const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( - WalletMessages.events.connectWalletDialogUpdated, - ) - //#endregion - - //#region wallet connect QR code dialog - const { setDialog: setWalletConnectDialog } = useRemoteControlledDialog( - WalletMessages.events.walletConnectQRCodeDialogUpdated, - ) - //#endregion - - const wallets = useWallets(ProviderType.MaskWallet) - const selectedNetworkType = useValueRef(currentNetworkSettings) - - //#region undetermined network type - const [undeterminedNetworkType, setUndeterminedNetworkType] = useState(selectedNetworkType) - useEffect(() => { - if (!open) return - setUndeterminedNetworkType(selectedNetworkType) - }, [open]) - //#endregion - - const { value: networks } = useAsync(async () => WalletRPC.getSupportedNetworks(), []) - - const onConnectProvider = useCallback( - async (providerType: ProviderType) => { - closeDialog() - - switch (providerType) { - case ProviderType.MaskWallet: - await Services.Helper.openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { - chainId: getChainIdFromNetworkType(undeterminedNetworkType), - }) - break - case ProviderType.MetaMask: - case ProviderType.WalletConnect: - setConnectWalletDialog({ - open: true, - providerType, - networkType: undeterminedNetworkType, - }) - break - case ProviderType.CustomNetwork: - throw new Error('To be implemented.') - default: - unreachable(providerType) - } - }, - [ - chainId, - wallets, - closeDialog, - undeterminedNetworkType, - setWalletConnectDialog, - ], - ) - - return ( - <> - - - 1. Choose Network - - - {networks?.map((network) => ( - { - setUndeterminedNetworkType(network) - }}> -
    - - {undeterminedNetworkType === network && ( - - )} -
    -
    - ))} -
    -
    - - - 2. Choose Wallet - - - - } - name="Mask Network" - onClick={() => onConnectProvider(ProviderType.MaskWallet)} - /> - - {Flags.metamask_support_enabled ? ( - - } - name="MetaMask" - onClick={() => onConnectProvider(ProviderType.MetaMask)} - /> - - ) : null} - - } - name="WalletConnect" - onClick={() => onConnectProvider(ProviderType.WalletConnect)} - /> - - - - - ) -} diff --git a/packages/mask/src/plugins/EVM/UI/components/Provider.tsx b/packages/mask/src/plugins/EVM/UI/components/Provider.tsx deleted file mode 100644 index e24dfc7cfc36..000000000000 --- a/packages/mask/src/plugins/EVM/UI/components/Provider.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { Typography, Card, ButtonBase, ButtonBaseProps } from '@mui/material' -import { makeStyles } from '@masknet/theme' -import { useStylesExtends } from '@masknet/shared' -import { getMaskColor } from '@masknet/theme' - -const useStyles = makeStyles()((theme) => ({ - root: { - textAlign: 'center', - }, - content: { - width: '100%', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - padding: theme.spacing(4, 1), - backgroundColor: getMaskColor(theme).twitterBackground, - }, - logo: { - width: 45, - height: 45, - marginBottom: theme.spacing(2), - }, - name: { - fontSize: 16, - fontWeight: 'normal', - whiteSpace: 'nowrap', - marginBottom: theme.spacing(1), - }, - description: { - fontSize: 14, - fontWeight: 300, - }, -})) - -export interface ProviderProps - extends withClasses { - logo: React.ReactNode - name: React.ReactNode - description?: React.ReactNode - onClick?: () => void - ButtonBaseProps?: Partial -} - -export function Provider(props: ProviderProps) { - const classes = useStylesExtends(useStyles(), props) - return ( - - -
    {props.logo}
    - - {props.name} - - {props.description && ( - - {props.description} - - )} -
    -
    - ) -} diff --git a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx new file mode 100644 index 000000000000..4e9bd2f53fc5 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx @@ -0,0 +1,61 @@ +import { useCallback, cloneElement, isValidElement } from 'react' +import type { Plugin } from '@masknet/plugin-infra/src' +import { PopupRoutes } from '@masknet/shared-base' +import { useRemoteControlledDialog } from '@masknet/shared' +import { getChainIdFromNetworkType, NetworkType, ProviderType, useWallets } from '@masknet/web3-shared-evm' +import Services from '../../../../extension/service' +import { WalletMessages } from '../../../Wallet/messages' +import { unreachable } from '@dimensiondev/kit' + +export interface ProviderIconClickBaitProps { + network: Plugin.Shared.Network + provider: Plugin.Shared.Provider + children?: React.ReactNode +} + +export function ProviderIconClickBait({ network, provider, children }: ProviderIconClickBaitProps) { + //#region connect wallet dialog + const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( + WalletMessages.events.connectWalletDialogUpdated, + ) + //#endregion + + const providerType = provider.type as ProviderType + const networkType = network.type as NetworkType + const wallets = useWallets(ProviderType.MaskWallet) + + const onClick = useCallback(async () => { + switch (providerType) { + case ProviderType.MaskWallet: + await Services.Helper.openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { + chainId: getChainIdFromNetworkType(network.type as NetworkType), + }) + break + case ProviderType.MetaMask: + case ProviderType.WalletConnect: + setConnectWalletDialog({ + open: true, + providerType, + networkType, + }) + break + case ProviderType.CustomNetwork: + throw new Error('To be implemented.') + default: + unreachable(providerType) + } + }, [networkType, providerType, wallets]) + + return ( + <> + {isValidElement(children) + ? cloneElement(children, { + ...children.props, + ...{ + onClick, + }, + }) + : children} + + ) +} diff --git a/packages/mask/src/plugins/EVM/assets/masknetwork.png b/packages/mask/src/plugins/EVM/assets/maskwallet.png similarity index 100% rename from packages/mask/src/plugins/EVM/assets/masknetwork.png rename to packages/mask/src/plugins/EVM/assets/maskwallet.png diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts index 01ea675e8f21..b59a833a74cf 100644 --- a/packages/mask/src/plugins/EVM/constants.ts +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -1,4 +1,4 @@ -import { NetworkType, ProviderType } from "@masknet/web3-shared-evm" +import { NetworkType, ProviderType } from '@masknet/web3-shared-evm' export const PLUGIN_META_KEY = 'com.maskbook.evm' export const PLUGIN_ID = 'com.maskbook.evm' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index 6ff3c2a51473..1e83b296e6f6 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -1,5 +1,6 @@ -import { useMemo, useState } from 'react' +import { useState } from 'react' import { SuccessIcon } from '@masknet/icons' +import { useValueRef } from '@masknet/shared' import { getMaskColor, makeStyles } from '@masknet/theme' import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' import { @@ -7,10 +8,10 @@ import { useRegisteredNetworks, useActivatedPluginsSNSAdaptor, useActivatedPluginsDashboard, - Plugin, } from '@masknet/plugin-infra' import { ProviderIcon } from './ProviderIcon' import { NetworkIcon } from './NetworkIcon' +import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' const useStyles = makeStyles()((theme) => ({ root: { @@ -73,29 +74,30 @@ const useStyles = makeStyles()((theme) => ({ }, })) -export interface PluginProviderRenderProps {} +export interface PluginProviderRenderProps { + onClose: () => void +} -export function PluginProviderRender(props: PluginProviderRenderProps) { +export function PluginProviderRender({ onClose }: PluginProviderRenderProps) { const { classes } = useStyles() - const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() - const pluginsDashboard = useActivatedPluginsDashboard() const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const [undeterminedPluginID, setUndeterminedPluginID] = useState('') - const [undeterminedNetworkID, setUndeterminedNetworkID] = useState('') - const onSwtich = useMemo(() => { - return (network?: Plugin.Shared.Network, provider?: Plugin.Shared.Provider) => { - if (!network || !provider) return - pluginsSNSAdaptor - .find((x) => x.ID === undeterminedPluginID) - ?.SelectNetworkDialogEntry?.onSelect(network, provider) - pluginsDashboard - .find((x) => x.ID === undeterminedPluginID) - ?.SelectNetworkDialogEntry?.onSelect(network, provider) - } - }, [undeterminedPluginID, pluginsSNSAdaptor, pluginsDashboard]) + const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() + const pluginsDashboard = useActivatedPluginsDashboard() + + const pluginID = useValueRef(pluginIDSettings) + const networkID = useValueRef(networkIDSettings) + const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) + const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) + + const NetworkIconClickBait = [...pluginsSNSAdaptor, ...pluginsDashboard].find( + (x) => x.ID === undeterminedPluginID, + )?.NetworkIconClickBait + const ProviderIconClickBait = [...pluginsSNSAdaptor, ...pluginsDashboard].find( + (x) => x.ID === undeterminedPluginID, + )?.ProviderIconClickBait return ( @@ -113,7 +115,13 @@ export function PluginProviderRender(props: PluginProviderRenderProps) { setUndeterminedNetworkID(network.ID) }}>
    - + {NetworkIconClickBait ? ( + + + + ) : ( + + )} {undeterminedNetworkID === network.ID && ( )} @@ -126,21 +134,20 @@ export function PluginProviderRender(props: PluginProviderRenderProps) { 2. Choose Wallet - + {providers .filter((x) => x.pluginID === undeterminedPluginID) .map((provider) => ( - - onSwtich( - networks.find((x) => x.ID === undeterminedNetworkID), - provider, - ) - } - /> + {ProviderIconClickBait ? ( + x.ID === undeterminedNetworkID)!} + provider={provider}> + + + ) : ( + + )} ))} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 59c5eb8dfe6e..e8424671ddaf 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -22,7 +22,7 @@ interface SelectProviderDialogUIProps extends withClasses {} function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { const { t } = useI18N() - const classes = useStyles() + const { classes } = useStyles() //#region remote controlled dialog logic const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) @@ -41,7 +41,7 @@ function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { return ( - + ) diff --git a/packages/mask/src/settings/settings.ts b/packages/mask/src/settings/settings.ts index c969cf1e9332..a2512f50663f 100644 --- a/packages/mask/src/settings/settings.ts +++ b/packages/mask/src/settings/settings.ts @@ -5,6 +5,7 @@ import { LaunchPage } from './types' import { Appearance } from '@masknet/theme' import { LanguageOptions } from '@masknet/public-api' import { Identifier, ProfileIdentifier } from '@masknet/shared-base' +import { PLUGIN_ID } from '../plugins/EVM/constants' /** * Does the debug mode on @@ -36,6 +37,15 @@ export const languageSettings = createGlobalSettings('language' }) //#endregion +//#region web3 +export const pluginIDSettings = createGlobalSettings('pluginID', PLUGIN_ID, { + primary: () => 'DO NOT DISPLAY IT IN UI', +}) +export const networkIDSettings = createGlobalSettings('networkID', `${PLUGIN_ID}_ethereum`, { + primary: () => 'DO NOT DISPLAY IT IN UI', +}) +//#endregion + //#region network setting /** diff --git a/packages/mask/src/tsconfig.json b/packages/mask/src/tsconfig.json index 5c9197dadf74..d356632d69d3 100644 --- a/packages/mask/src/tsconfig.json +++ b/packages/mask/src/tsconfig.json @@ -7,7 +7,7 @@ "emitDeclarationOnly": true, "lib": ["ES2021"] }, - "include": ["./", "./**/*.json", "plugins/Wallet/SNSAdaptor/SelectProviderDialog"], + "include": ["./", "./**/*.json"], // ! Note: mask/ depends dashboard/ on source-code level // ! but dashboard/ depends mask/ on type level // ! do not add dashboard/ as a reference otherwise there is a circular dependency on the type level. diff --git a/packages/plugin-infra/README.md b/packages/plugin-infra/README.md index 77cb49547364..75cb5e48ba6f 100644 --- a/packages/plugin-infra/README.md +++ b/packages/plugin-infra/README.md @@ -7,6 +7,6 @@ ## How to write a new plugin? (In Mask) -1. Create a new folder under `packages/mask/plugins/YOUR_PLUGIN_NAME`. +1. Create a new folder under `packages/plugins/YOUR_PLUGIN_NAME`. 2. Copy `packages/plugins/example/src/*` under your plugin folder. 3. Read `packages/plugin-infra/src/types.ts` to learn the Plugin API of Mask. diff --git a/packages/plugin-infra/src/manager/manage.ts b/packages/plugin-infra/src/manager/manage.ts index 92b63a7af2ca..e035462e7957 100644 --- a/packages/plugin-infra/src/manager/manage.ts +++ b/packages/plugin-infra/src/manager/manage.ts @@ -43,16 +43,18 @@ export function createManager, extraCheck?: (id: string) => boolean) { _host = host const { enabled, signal, addI18NResource } = _host - const off2 = enabled.events.on(ALL_EVENTS, checkRequirementAndStartOrStop) signal?.addEventListener('abort', () => [...activated.keys()].forEach(stopPlugin)) - signal?.addEventListener('abort', off2) + signal?.addEventListener('abort', enabled.events.on(ALL_EVENTS, checkRequirementAndStartOrStop)) for (const plugin of registeredPlugins) { plugin.i18n && addI18NResource(plugin.ID, plugin.i18n) } checkRequirementAndStartOrStop().catch(console.error) async function checkRequirementAndStartOrStop() { + console.log('') + + for (const id of registeredPluginIDs) { if (await meetRequirement(id)) activatePlugin(id).catch(console.error) else stopPlugin(id) diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index fb2b0910c0f4..4496ebe72ff9 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -5,9 +5,11 @@ const __registered = new Map() export const registeredPlugins: Iterable = { [Symbol.iterator]: () => __registered.values() } export const registeredPluginIDs: Iterable = { [Symbol.iterator]: () => __registered.keys() } + export function getPluginDefine(id: string) { return __registered.get(id) } + export function registerPlugin(def: Plugin.DeferredDefinition) { if (__registered.has(def.ID)) return if (!__meetRegisterRequirement(def)) return diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index fb96d034f971..34f38e15532d 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -206,10 +206,16 @@ export namespace Plugin.SNSAdaptor { SearchBoxComponent?: InjectUI<{}> /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> + /** This Ui will receve network icon as children component, and the plugin may hook click handle on it. */ + NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> + /** This Ui will receve provider icon as children component, and the plugin may hook click handle on it. */ + ProviderIconClickBait?: React.ComponentType<{ + network: Shared.Network + provider: Shared.Provider + children?: React.ReactNode + }> /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry - /** This UI will be an entry of network in the Select Provider Dialog. */ - SelectNetworkDialogEntry?: SelectNetworkDialogEntry /** This UI will be use when there is known badges. */ CompositionDialogMetadataBadgeRender?: CompositionMetadataBadgeRender /** This UI will be rendered as an entry in the toolbar (if the SNS has a Toolbar support) */ @@ -248,17 +254,6 @@ export namespace Plugin.SNSAdaptor { */ keepMounted?: boolean } - - export interface SelectNetworkDialogEntry { - /** - * This function will be called when the user chooses a new network with a specific wallet provider. - * The plugin must provide a data persistence solution. And that data should only alter in this callback. - * The infra will take its duty to track which network is used at the current stage. - * @param network - * @param provider - */ - onSelect(network: Shared.Network, provider: Shared.Provider): Promise - } export interface CompositionDialogEntry_DialogProps { open: boolean onClose(): void @@ -309,8 +304,14 @@ export namespace Plugin.Dashboard { export interface Definition extends Shared.DefinitionDeferred { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> - /** This UI will be an entry of network in the Select Provider Dialog. */ - SelectNetworkDialogEntry?: Plugin.SNSAdaptor.SelectNetworkDialogEntry + /** This Ui will receve network icon as children component, and the plugin may hook click handle on it. */ + NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> + /** This Ui will receve provider icon as children component, and the plugin may hook click handle on it. */ + ProviderIconClickBait?: React.ComponentType<{ + network: Shared.Network + provider: Shared.Provider + children?: React.ReactNode + }> } } diff --git a/packages/plugins/Flow/package.json b/packages/plugins/Flow/package.json index 70533b129893..a810f50e98e5 100644 --- a/packages/plugins/Flow/package.json +++ b/packages/plugins/Flow/package.json @@ -4,13 +4,12 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { + "@masknet/icons": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/shared": "workspace:*", "@masknet/shared-base": "workspace:*", "@masknet/theme": "workspace:*", - "@masknet/icons": "workspace:*", "@masknet/web3-shared-flow": "workspace:*", - "@onflow/fcl": "^0.0.77", "bignumber.js": "^9.0.1", "react-use": "^17.3.1" } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index a1ee6f37ce1f..a3510816e644 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,14 +1,11 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -const sns: Plugin.SNSAdaptor.Definition = { +const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, - SelectNetworkDialogEntry: { - async onSelect(network, provider) { - console.log(`FLOW DASHBOARD: ${network.ID} ${provider.ID}`) - }, - }, + ProviderIconClickBait, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index eba1b731b21f..9e442d4fd95d 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,16 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { PluginIcon } from '../components/PluginIcon' -import { PluginPanel } from '../components/PluginPanel' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - SelectNetworkDialogEntry: { - async onSelect(network, provider) { - console.log(`FLOW: ${network.ID} ${provider.ID}`) - }, - }, + ProviderIconClickBait, } export default sns diff --git a/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx b/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx deleted file mode 100644 index de68b5b644ec..000000000000 --- a/packages/plugins/Flow/src/UI/components/NetworkIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import type { ChainId, ProviderType } from '@masknet/web3-shared-flow' - -export interface NetworkIconProps { - size: number - chainId: ChainId - // if exists, a small provider icon will add a provider cion on the right bottom side - providerType?: ProviderType -} - -export function NetworkIcon(props: NetworkIconProps) { - return <> -} diff --git a/packages/plugins/Flow/src/UI/components/PluginIcon.tsx b/packages/plugins/Flow/src/UI/components/PluginIcon.tsx deleted file mode 100644 index 62f73c91e404..000000000000 --- a/packages/plugins/Flow/src/UI/components/PluginIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { makeStyles } from '@masknet/theme' - -const useStyles = makeStyles()({ - image: { - width: 24, - height: 24, - }, -}) - -export interface PluginIconProps {} - -export function PluginIcon(props: PluginIconProps) { - const { classes } = useStyles() - const iconURL = new URL('../../assets/flow.png', import.meta.url).toString() - return -} diff --git a/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx b/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx deleted file mode 100644 index 3c257bc5d527..000000000000 --- a/packages/plugins/Flow/src/UI/components/ProviderIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { ProviderType, resolveProviderName } from '@masknet/web3-shared-flow' -import { Typography } from '@mui/material' - -export interface ProviderIconProps { - size: number - providerType: ProviderType -} - -export function ProviderIcon(props: ProviderIconProps) { - return {resolveProviderName(props.providerType)} -} diff --git a/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx new file mode 100644 index 000000000000..2351ccf4e2ef --- /dev/null +++ b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx @@ -0,0 +1,33 @@ +import { useCallback, cloneElement, isValidElement } from 'react' +import type { Plugin } from '@masknet/plugin-infra/src' +import { NetworkType, ProviderType, useFCL } from '@masknet/web3-shared-flow' + +export interface ProviderIconClickBaitProps { + network: Plugin.Shared.Network + provider: Plugin.Shared.Provider + children?: React.ReactNode +} + +export function ProviderIconClickBait({ network, provider, children }: ProviderIconClickBaitProps) { + const networkType = network.type as NetworkType + const providerType = network.type as ProviderType + + const fcl = useFCL() + const onLogIn = useCallback(() => fcl.logIn(), [fcl]) + const onClick = useCallback(() => { + onLogIn() + }, [networkType, providerType, onLogIn]) + + return ( + <> + {isValidElement(children) + ? cloneElement(children, { + ...children.props, + ...{ + onClick, + }, + }) + : children} + + ) +} diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts index 8573d031a2c3..b6e0553edd6f 100644 --- a/packages/plugins/Flow/src/constants.ts +++ b/packages/plugins/Flow/src/constants.ts @@ -1,4 +1,4 @@ -import { NetworkType, ProviderType} from '@masknet/web3-shared-flow' +import { NetworkType, ProviderType } from '@masknet/web3-shared-flow/types' export const PLUGIN_META_KEY = 'com.maskbook.flow' export const PLUGIN_ID = 'com.maskbook.flow' diff --git a/packages/plugins/Flow/tsconfig.json b/packages/plugins/Flow/tsconfig.json index 1931aea5c1a4..bdc5ac845c1d 100644 --- a/packages/plugins/Flow/tsconfig.json +++ b/packages/plugins/Flow/tsconfig.json @@ -1,13 +1,14 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "rootDir": "./src/", - "outDir": "./dist/", - "tsBuildInfoFile": "./dist/.tsbuildinfo", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo", "resolveJsonModule": true }, - "include": ["./src", "./src/**/*.json"], + "include": ["src", "src/**/*.json"], "references": [ + { "path": "../../icons" }, { "path": "../../plugin-infra" }, { "path": "../../shared" }, { "path": "../../shared-base" }, diff --git a/packages/plugins/Wallet/tsconfig.json b/packages/plugins/Wallet/tsconfig.json index e4827a85c5d7..9cc0afe3d0f1 100644 --- a/packages/plugins/Wallet/tsconfig.json +++ b/packages/plugins/Wallet/tsconfig.json @@ -1,12 +1,12 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "rootDir": "./src/", - "outDir": "./dist/", - "tsBuildInfoFile": "./dist/.tsbuildinfo", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo", "resolveJsonModule": true }, - "include": ["./src", "./src/**/*.json"], + "include": ["src", "src/**/*.json"], "references": [ { "path": "../../plugin-infra" }, { "path": "../../web3-shared/evm" }, diff --git a/packages/shared/src/UI/components/SelectProviderDialog/index.tsx b/packages/shared/src/UI/components/SelectProviderDialog/index.tsx deleted file mode 100644 index 59c5eb8dfe6e..000000000000 --- a/packages/shared/src/UI/components/SelectProviderDialog/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { useEffect } from 'react' -import { makeStyles } from '@masknet/theme' -import { DialogContent } from '@mui/material' -import { useI18N } from '../../../../utils/i18n-next-ui' -import { WalletMessages } from '../../messages' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' -import { hasNativeAPI, nativeAPI } from '../../../../utils' -import { PluginProviderRender } from './PluginProviderRender' -import { useRemoteControlledDialog } from '@masknet/shared' - -const useStyles = makeStyles()((theme) => ({ - content: { - padding: theme.spacing(0), - scrollbarWidth: 'none', - '&::-webkit-scrollbar': { - display: 'none', - }, - }, -})) - -interface SelectProviderDialogUIProps extends withClasses {} - -function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { - const { t } = useI18N() - const classes = useStyles() - - //#region remote controlled dialog logic - const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) - //#endregion - - //#region native app - useEffect(() => { - if (!open) return - if (hasNativeAPI) nativeAPI?.api.misc_openCreateWalletView() - }, [open]) - //#endregion - - // not available for the native app - if (hasNativeAPI) return null - - return ( - - - - - - ) -} - -export interface SelectProviderDialogProps extends SelectProviderDialogUIProps {} - -export function SelectProviderDialog(props: SelectProviderDialogProps) { - return -} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index f81e2f93aa40..9c37d1905d8c 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "./dist/", "tsBuildInfoFile": "./dist/.tsbuildinfo" }, - "include": ["./src", "./src/**/*.json", "../mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog"], + "include": ["./src", "./src/**/*.json"], "references": [ { "path": "../web3-shared/evm" }, { "path": "../theme" }, diff --git a/packages/web3-kit/src/index.ts b/packages/web3-kit/src/index.ts index b2a4c7512849..493732df2b6e 100644 --- a/packages/web3-kit/src/index.ts +++ b/packages/web3-kit/src/index.ts @@ -1 +1,2 @@ export * from './helpers' +export * from './types' diff --git a/packages/web3-shared/flow/index.ts b/packages/web3-shared/flow/index.ts index b0d95eccd958..e71ede70f0d2 100644 --- a/packages/web3-shared/flow/index.ts +++ b/packages/web3-shared/flow/index.ts @@ -1,3 +1,3 @@ -export * from './hooks' export * from './types' export * from './pipes' +export * from './hooks' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b42be6c6969f..401268eaffcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -567,7 +567,6 @@ importers: '@masknet/shared-base': workspace:* '@masknet/theme': workspace:* '@masknet/web3-shared-flow': workspace:* - '@onflow/fcl': ^0.0.77 bignumber.js: ^9.0.1 react-use: ^17.3.1 dependencies: @@ -577,7 +576,6 @@ importers: '@masknet/shared-base': link:../../shared-base '@masknet/theme': link:../../theme '@masknet/web3-shared-flow': link:../../web3-shared/flow - '@onflow/fcl': 0.0.77 bignumber.js: 9.0.1 react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 From e37ee3d4fbb77d44deb10292456efb21440fb5b1 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 5 Nov 2021 16:49:34 +0800 Subject: [PATCH 04/41] fix: type error --- packages/plugins/Flow/src/env.d.ts | 1 + packages/web3-kit/package.json | 4 ++-- packages/web3-kit/tsconfig.json | 4 ++-- packages/web3-shared/flow/tsconfig.json | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 packages/plugins/Flow/src/env.d.ts diff --git a/packages/plugins/Flow/src/env.d.ts b/packages/plugins/Flow/src/env.d.ts new file mode 100644 index 000000000000..868322d5ff30 --- /dev/null +++ b/packages/plugins/Flow/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/web3-kit/package.json b/packages/web3-kit/package.json index 6d0062360c10..8765238aa53a 100644 --- a/packages/web3-kit/package.json +++ b/packages/web3-kit/package.json @@ -1,6 +1,6 @@ { "name": "@masknet/web3-kit", "private": true, - "main": "./dist/src/index.js", - "types": "./dist/src/index.d.ts" + "main": "./dist/index.js", + "types": "./dist/index.d.ts" } diff --git a/packages/web3-kit/tsconfig.json b/packages/web3-kit/tsconfig.json index 194f92619e6e..a60b8d557dca 100644 --- a/packages/web3-kit/tsconfig.json +++ b/packages/web3-kit/tsconfig.json @@ -2,8 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "rootDir": "./src/", - "outDir": "./dist/src/", - "tsBuildInfoFile": "./dist/src.tsbuildinfo" + "outDir": "./dist/", + "tsBuildInfoFile": "./dist/.tsbuildinfo" }, "include": ["./src", "./src/**/*.json"] } diff --git a/packages/web3-shared/flow/tsconfig.json b/packages/web3-shared/flow/tsconfig.json index 3548636e4fb0..4df8fbc1cc60 100644 --- a/packages/web3-shared/flow/tsconfig.json +++ b/packages/web3-shared/flow/tsconfig.json @@ -5,5 +5,6 @@ "outDir": "../dist/flow", "tsBuildInfoFile": "../dist/flow.tsbuildinfo" }, - "include": ["./", "./**/*.json"] + "include": ["./", "./**/*.json"], + "references": [{ "path": "../../web3-kit" }] } From fbc9f7ec1ae1b4fac5943275345b5c2958b4067c Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Fri, 5 Nov 2021 17:25:09 +0800 Subject: [PATCH 05/41] refactor: Web3Provider --- .../src/plugins/EVM/UI/Dashboard/index.tsx | 4 +- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 4 +- .../src/plugins/EVM/UI/Web3Provider/index.tsx | 18 +++ .../UI/components/ProviderIconClickBait.tsx | 2 +- .../SelectProviderDialog/NetworkIcon.tsx | 1 + .../PluginProviderRender.tsx | 129 +++++++++--------- .../PluginProviderWatcher.tsx | 22 +++ .../SNSAdaptor/SelectProviderDialog/index.tsx | 2 +- .../plugin-infra/src/manager/dashboard.ts | 7 + packages/plugin-infra/src/manager/manage.ts | 1 - .../plugin-infra/src/manager/sns-adaptor.ts | 5 + packages/plugin-infra/src/types.ts | 47 ++++--- .../plugins/Flow/src/UI/Dashboard/index.tsx | 4 +- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 4 +- .../Flow/src/UI/Web3Provider/index.tsx | 18 +++ packages/plugins/Flow/src/constants.ts | 5 +- packages/web3-shared/flow/hooks/index.ts | 2 + .../web3-shared/flow/hooks/useNetworkType.ts | 5 + .../web3-shared/flow/hooks/useProviderType.ts | 5 + 19 files changed, 193 insertions(+), 92 deletions(-) create mode 100644 packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx create mode 100644 packages/plugins/Flow/src/UI/Web3Provider/index.tsx create mode 100644 packages/web3-shared/flow/hooks/useNetworkType.ts create mode 100644 packages/web3-shared/flow/hooks/useProviderType.ts diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index 9e442d4fd95d..b6f78e11befb 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { ProviderIconClickBait } from '../components/ProviderIconClickBait' +import { Web3Provider } from '../Web3Provider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - ProviderIconClickBait, + Web3Provider, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index 9e442d4fd95d..b6f78e11befb 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { ProviderIconClickBait } from '../components/ProviderIconClickBait' +import { Web3Provider } from '../Web3Provider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - ProviderIconClickBait, + Web3Provider, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx new file mode 100644 index 000000000000..335cfa707e9c --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx @@ -0,0 +1,18 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { useNetworkType, useProviderType } from '@masknet/web3-shared-evm' +import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' + +export const Web3Provider: Plugin.Shared.Web3Provider = { + SelectProviderDialog: { + useNetwork() { + const networkType = useNetworkType() + return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null + }, + useProvider() { + const providerType = useProviderType() + return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null + }, + ProviderIconClickBait, + }, +} diff --git a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx index 4e9bd2f53fc5..c279760fd891 100644 --- a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx +++ b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx @@ -1,11 +1,11 @@ import { useCallback, cloneElement, isValidElement } from 'react' +import { unreachable } from '@dimensiondev/kit' import type { Plugin } from '@masknet/plugin-infra/src' import { PopupRoutes } from '@masknet/shared-base' import { useRemoteControlledDialog } from '@masknet/shared' import { getChainIdFromNetworkType, NetworkType, ProviderType, useWallets } from '@masknet/web3-shared-evm' import Services from '../../../../extension/service' import { WalletMessages } from '../../../Wallet/messages' -import { unreachable } from '@dimensiondev/kit' export interface ProviderIconClickBaitProps { network: Plugin.Shared.Network diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx index 9473a86c5e32..8731ed6198d2 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx @@ -15,6 +15,7 @@ export interface NetworkIconProps { size?: number icon: string } + export function NetworkIcon({ size = 48, icon }: NetworkIconProps) { const { classes } = useStyles() return diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index 1e83b296e6f6..f4290c4721c7 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -6,11 +6,12 @@ import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/ import { useRegisteredProviders, useRegisteredNetworks, - useActivatedPluginsSNSAdaptor, - useActivatedPluginsDashboard, + useActivatedPluginSNSAdaptor, + useActivatedPluginDashboard, } from '@masknet/plugin-infra' import { ProviderIcon } from './ProviderIcon' import { NetworkIcon } from './NetworkIcon' +import { PluginProviderWatcher } from './PluginProviderWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' const useStyles = makeStyles()((theme) => ({ @@ -84,74 +85,78 @@ export function PluginProviderRender({ onClose }: PluginProviderRenderProps) { const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() - const pluginsDashboard = useActivatedPluginsDashboard() - const pluginID = useValueRef(pluginIDSettings) const networkID = useValueRef(networkIDSettings) const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) - const NetworkIconClickBait = [...pluginsSNSAdaptor, ...pluginsDashboard].find( - (x) => x.ID === undeterminedPluginID, - )?.NetworkIconClickBait - const ProviderIconClickBait = [...pluginsSNSAdaptor, ...pluginsDashboard].find( - (x) => x.ID === undeterminedPluginID, - )?.ProviderIconClickBait + const pluginSNSAdaptor = useActivatedPluginSNSAdaptor(undeterminedPluginID) + const pluginDashboard = useActivatedPluginDashboard(undeterminedPluginID) + + const { useNetwork, useProvider, NetworkIconClickBait, ProviderIconClickBait } = + (pluginSNSAdaptor ?? pluginDashboard)?.Web3Provider?.SelectProviderDialog ?? {} return ( - -
    - - 1. Choose Network - - - {networks?.map((network) => ( - { - setUndeterminedPluginID(network.pluginID) - setUndeterminedNetworkID(network.ID) - }}> -
    - {NetworkIconClickBait ? ( - + <> + + +
    + + 1. Choose Network + + + {networks?.map((network) => ( + { + setUndeterminedPluginID(network.pluginID) + setUndeterminedNetworkID(network.ID) + }}> +
    + {NetworkIconClickBait ? ( + + + + ) : ( - - ) : ( - - )} - {undeterminedNetworkID === network.ID && ( - - )} -
    -
    - ))} -
    -
    -
    - - 2. Choose Wallet - - - {providers - .filter((x) => x.pluginID === undeterminedPluginID) - .map((provider) => ( - - {ProviderIconClickBait ? ( - x.ID === undeterminedNetworkID)!} - provider={provider}> - - - ) : ( - - )} - + )} + {undeterminedNetworkID === network.ID && ( + + )} +
    +
    ))} - -
    -
    + + +
    + + 2. Choose Wallet + + + {providers + .filter((x) => x.pluginID === undeterminedPluginID) + .map((provider) => ( + + {ProviderIconClickBait ? ( + x.ID === undeterminedNetworkID)!} + provider={provider}> + + + ) : ( + + )} + + ))} + +
    + + ) } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx new file mode 100644 index 000000000000..930c17f19095 --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx @@ -0,0 +1,22 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { useRef } from 'react' + +export interface PluginProviderWatcherProps { + useNetwork?: () => Plugin.Shared.Network | null + useProvider?: () => Plugin.Shared.Provider | null + expectedPluginID: string + expectedNetworkID: string +} + +export function PluginProviderWatcher({ useNetwork, useProvider }: PluginProviderWatcherProps) { + const network = useRef<() => Plugin.Shared.Network | null>(useNetwork ?? (() => null)).current() + const provider = useRef<() => Plugin.Shared.Provider | null>(useProvider ?? (() => null)).current() + + console.log('DEBUG: PluginProviderWatcher') + console.log({ + network, + provider, + }) + + return null +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index e8424671ddaf..f91e111af9f2 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,12 +1,12 @@ import { useEffect } from 'react' import { makeStyles } from '@masknet/theme' import { DialogContent } from '@mui/material' +import { useRemoteControlledDialog } from '@masknet/shared' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' -import { useRemoteControlledDialog } from '@masknet/shared' const useStyles = makeStyles()((theme) => ({ content: { diff --git a/packages/plugin-infra/src/manager/dashboard.ts b/packages/plugin-infra/src/manager/dashboard.ts index 6a4c38fd7893..c829fc11787a 100644 --- a/packages/plugin-infra/src/manager/dashboard.ts +++ b/packages/plugin-infra/src/manager/dashboard.ts @@ -9,9 +9,16 @@ const subscription: Subscription = { getCurrentValue: () => [...activated.plugins], subscribe: (f) => events.on(ALL_EVENTS, f), } + export function useActivatedPluginsDashboard() { return useSubscription(subscription) } + +export function useActivatedPluginDashboard(pluginID: string) { + const plugins = useSubscription(subscription) + return plugins.find((x) => x.ID === pluginID) +} + export function startPluginDashboard(host: Plugin.__Host.Host) { startDaemon(host) } diff --git a/packages/plugin-infra/src/manager/manage.ts b/packages/plugin-infra/src/manager/manage.ts index e035462e7957..8bf69b26b290 100644 --- a/packages/plugin-infra/src/manager/manage.ts +++ b/packages/plugin-infra/src/manager/manage.ts @@ -54,7 +54,6 @@ export function createManager x.ID === pluginID) +} + export function useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet() { const chainId = useChainId() const plugins = useActivatedPluginsSNSAdaptor() diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 34f38e15532d..b543aea79dc3 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -1,7 +1,7 @@ import type React from 'react' import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' -import type { ChainId, Web3ProviderType } from '@masknet/web3-shared-evm' +import type { ChainId } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' export namespace Plugin { @@ -193,6 +193,30 @@ export namespace Plugin.Shared { /** The provider name */ name: string } + + export interface Web3Provider { + SelectProviderDialog?: { + /** A react hook returns the currently selected provider. */ + useProvider?: () => Shared.Provider | null + /** A react hook returns the currently selected network. */ + useNetwork?: () => Shared.Network | null + /** This UI will receve network icon as children component, and the plugin may hook click handle on it. */ + NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> + /** This UI will receve provider icon as children component, and the plugin may hook click handle on it. */ + ProviderIconClickBait?: React.ComponentType<{ + network: Shared.Network + provider: Shared.Provider + children?: React.ReactNode + }> + } + Dashboard?: { + /** There UIs will be injected into the wallet table of Dashboard. */ + OverviewComponent?: React.ComponentType<{}> + AssetsTableComponent?: React.ComponentType<{}> + TransferTableComponent?: React.ComponentType<{}> + HistoryTableComponent?: React.ComponentType<{}> + } + } } /** This part runs in the SNSAdaptor */ @@ -206,14 +230,8 @@ export namespace Plugin.SNSAdaptor { SearchBoxComponent?: InjectUI<{}> /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> - /** This Ui will receve network icon as children component, and the plugin may hook click handle on it. */ - NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> - /** This Ui will receve provider icon as children component, and the plugin may hook click handle on it. */ - ProviderIconClickBait?: React.ComponentType<{ - network: Shared.Network - provider: Shared.Provider - children?: React.ReactNode - }> + /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ + Web3Provider?: Shared.Web3Provider /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -304,14 +322,9 @@ export namespace Plugin.Dashboard { export interface Definition extends Shared.DefinitionDeferred { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> - /** This Ui will receve network icon as children component, and the plugin may hook click handle on it. */ - NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> - /** This Ui will receve provider icon as children component, and the plugin may hook click handle on it. */ - ProviderIconClickBait?: React.ComponentType<{ - network: Shared.Network - provider: Shared.Provider - children?: React.ReactNode - }> + + /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ + Web3Provider?: Shared.Web3Provider } } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index a3510816e644..e581ac9e82ff 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' -import { ProviderIconClickBait } from '../components/ProviderIconClickBait' +import { Web3Provider } from '../Web3Provider' const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, - ProviderIconClickBait, + Web3Provider, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index 9e442d4fd95d..b6f78e11befb 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { ProviderIconClickBait } from '../components/ProviderIconClickBait' +import { Web3Provider } from '../Web3Provider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - ProviderIconClickBait, + Web3Provider, } export default sns diff --git a/packages/plugins/Flow/src/UI/Web3Provider/index.tsx b/packages/plugins/Flow/src/UI/Web3Provider/index.tsx new file mode 100644 index 000000000000..0445993c28b9 --- /dev/null +++ b/packages/plugins/Flow/src/UI/Web3Provider/index.tsx @@ -0,0 +1,18 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { useNetworkType, useProviderType } from '@masknet/web3-shared-flow' +import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' +import { ProviderIconClickBait } from '../components/ProviderIconClickBait' + +export const Web3Provider: Plugin.Shared.Web3Provider = { + SelectProviderDialog: { + useNetwork() { + const networkType = useNetworkType() + return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null + }, + useProvider() { + const providerType = useProviderType() + return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null + }, + ProviderIconClickBait, + }, +} diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts index b6e0553edd6f..ea81744e1291 100644 --- a/packages/plugins/Flow/src/constants.ts +++ b/packages/plugins/Flow/src/constants.ts @@ -1,3 +1,4 @@ +import type { Plugin } from '@masknet/plugin-infra' import { NetworkType, ProviderType } from '@masknet/web3-shared-flow/types' export const PLUGIN_META_KEY = 'com.maskbook.flow' @@ -5,7 +6,7 @@ export const PLUGIN_ID = 'com.maskbook.flow' export const PLUGIN_NAME = 'Flow Chain' export const PLUGIN_ICON = 'F' export const PLUGIN_DESCRIPTION = '' -export const PLUGIN_NETWORKS = [ +export const PLUGIN_NETWORKS: Plugin.Shared.Network[] = [ { ID: `${PLUGIN_ID}_flow`, type: NetworkType.Flow, @@ -13,7 +14,7 @@ export const PLUGIN_NETWORKS = [ icon: new URL('./assets/flow.png', import.meta.url).toString(), }, ] -export const PLUGIN_PROVIDERS = [ +export const PLUGIN_PROVIDERS: Plugin.Shared.Provider[] = [ { ID: `${PLUGIN_ID}_blocto`, type: ProviderType.Blocto, diff --git a/packages/web3-shared/flow/hooks/index.ts b/packages/web3-shared/flow/hooks/index.ts index 8128752358cb..1a0a7b591570 100644 --- a/packages/web3-shared/flow/hooks/index.ts +++ b/packages/web3-shared/flow/hooks/index.ts @@ -5,3 +5,5 @@ export * from './useChainConfig' export * from './useCurrentUser' export * from './useFCL' export * from './useScript' +export * from './useNetworkType' +export * from './useProviderType' diff --git a/packages/web3-shared/flow/hooks/useNetworkType.ts b/packages/web3-shared/flow/hooks/useNetworkType.ts new file mode 100644 index 000000000000..da471cc6db1f --- /dev/null +++ b/packages/web3-shared/flow/hooks/useNetworkType.ts @@ -0,0 +1,5 @@ +import { NetworkType } from '../types' + +export function useNetworkType() { + return NetworkType.Flow +} diff --git a/packages/web3-shared/flow/hooks/useProviderType.ts b/packages/web3-shared/flow/hooks/useProviderType.ts new file mode 100644 index 000000000000..ed31b3d0f565 --- /dev/null +++ b/packages/web3-shared/flow/hooks/useProviderType.ts @@ -0,0 +1,5 @@ +import { ProviderType } from '../types' + +export function useProviderType() { + return ProviderType.Blocto +} From 5e1f5d6f54426a6472de6caa829b4243d53fa6b0 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sat, 6 Nov 2021 16:30:27 +0800 Subject: [PATCH 06/41] chore: web3 connection --- .../src/plugins/EVM/UI/Web3Provider/index.tsx | 13 +--- packages/mask/src/plugins/EVM/constants.ts | 8 +++ packages/mask/src/plugins/EVM/hooks/index.ts | 2 + .../mask/src/plugins/EVM/hooks/useNetwork.ts | 7 +++ .../mask/src/plugins/EVM/hooks/useProvider.ts | 7 +++ .../PluginNetworkWatcher.tsx | 21 +++++++ .../PluginProviderRender.tsx | 59 ++++++++----------- .../PluginProviderWatcher.tsx | 22 ------- .../SNSAdaptor/SelectProviderDialog/index.tsx | 58 ++++++++++++++---- packages/plugin-infra/src/manager/store.ts | 18 +----- packages/plugin-infra/src/types.ts | 4 ++ packages/plugins/Flow/src/constants.ts | 2 + 12 files changed, 129 insertions(+), 92 deletions(-) create mode 100644 packages/mask/src/plugins/EVM/hooks/index.ts create mode 100644 packages/mask/src/plugins/EVM/hooks/useNetwork.ts create mode 100644 packages/mask/src/plugins/EVM/hooks/useProvider.ts create mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx delete mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx diff --git a/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx index 335cfa707e9c..858a8431d1c3 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx @@ -1,18 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' -import { useNetworkType, useProviderType } from '@masknet/web3-shared-evm' -import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' +import { useNetwork, useProvider } from '../../hooks' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' export const Web3Provider: Plugin.Shared.Web3Provider = { SelectProviderDialog: { - useNetwork() { - const networkType = useNetworkType() - return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null - }, - useProvider() { - const providerType = useProviderType() - return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null - }, + useNetwork, + useProvider, ProviderIconClickBait, }, } diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts index b59a833a74cf..10c8ba9eed89 100644 --- a/packages/mask/src/plugins/EVM/constants.ts +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -8,30 +8,35 @@ export const PLUGIN_DESCRIPTION = '' export const PLUGIN_NETWORKS = [ { ID: `${PLUGIN_ID}_ethereum`, + pluginID: PLUGIN_ID, type: NetworkType.Ethereum, name: 'Ethereum', icon: new URL('./assets/ethereum.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_bsc`, + pluginID: PLUGIN_ID, type: NetworkType.Binance, name: 'BSC', icon: new URL('./assets/binance.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_polygon`, + pluginID: PLUGIN_ID, type: NetworkType.Polygon, name: 'Polygon', icon: new URL('./assets/polygon.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_arbitrum`, + pluginID: PLUGIN_ID, type: NetworkType.Arbitrum, name: 'Arbitrum One', icon: new URL('./assets/arbitrum.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_xdai`, + pluginID: PLUGIN_ID, type: NetworkType.xDai, name: 'xDai', icon: new URL('./assets/xdai.png', import.meta.url).toString(), @@ -40,18 +45,21 @@ export const PLUGIN_NETWORKS = [ export const PLUGIN_PROVIDERS = [ { ID: `${PLUGIN_ID}_maskwallet`, + pluginID: PLUGIN_ID, type: ProviderType.MaskWallet, name: 'Mask Network', icon: new URL('./assets/maskwallet.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_metamask`, + pluginID: PLUGIN_ID, type: ProviderType.MetaMask, name: 'MetaMask', icon: new URL('./assets/metamask.png', import.meta.url).toString(), }, { ID: `${PLUGIN_ID}_walletconnect`, + pluginID: PLUGIN_ID, type: ProviderType.WalletConnect, name: 'WalletConnect', icon: new URL('./assets/walletconnect.png', import.meta.url).toString(), diff --git a/packages/mask/src/plugins/EVM/hooks/index.ts b/packages/mask/src/plugins/EVM/hooks/index.ts new file mode 100644 index 000000000000..429a7ed5db45 --- /dev/null +++ b/packages/mask/src/plugins/EVM/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './useNetwork' +export * from './useProvider' diff --git a/packages/mask/src/plugins/EVM/hooks/useNetwork.ts b/packages/mask/src/plugins/EVM/hooks/useNetwork.ts new file mode 100644 index 000000000000..c7aabe856c6b --- /dev/null +++ b/packages/mask/src/plugins/EVM/hooks/useNetwork.ts @@ -0,0 +1,7 @@ +import { useNetworkType } from '@masknet/web3-shared-evm' +import { PLUGIN_NETWORKS } from '../constants' + +export function useNetwork() { + const networkType = useNetworkType() + return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null +} diff --git a/packages/mask/src/plugins/EVM/hooks/useProvider.ts b/packages/mask/src/plugins/EVM/hooks/useProvider.ts new file mode 100644 index 000000000000..6cb1ade139bc --- /dev/null +++ b/packages/mask/src/plugins/EVM/hooks/useProvider.ts @@ -0,0 +1,7 @@ +import { useProviderType } from '@masknet/web3-shared-evm' +import { PLUGIN_PROVIDERS } from '../constants' + +export function useProvider() { + const providerType = useProviderType() + return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx new file mode 100644 index 000000000000..bf70655bca69 --- /dev/null +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx @@ -0,0 +1,21 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { useEffect } from 'react' +import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' + +export interface PluginNetworkWatcherProps { + useNetwork: () => Plugin.Shared.Network | null + expectedPluginID: string + expectedNetworkID: string +} + +export function PluginNetworkWatcher({ useNetwork, expectedPluginID, expectedNetworkID }: PluginNetworkWatcherProps) { + const network = useNetwork() + + useEffect(() => { + const matched = network && network.pluginID === expectedPluginID && network.ID === expectedNetworkID + if (!matched) return + pluginIDSettings.value = expectedPluginID + networkIDSettings.value = expectedNetworkID + }, [network, expectedPluginID, expectedNetworkID]) + return null +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index f4290c4721c7..086e3edaf0f7 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -1,18 +1,9 @@ -import { useState } from 'react' import { SuccessIcon } from '@masknet/icons' -import { useValueRef } from '@masknet/shared' import { getMaskColor, makeStyles } from '@masknet/theme' import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' -import { - useRegisteredProviders, - useRegisteredNetworks, - useActivatedPluginSNSAdaptor, - useActivatedPluginDashboard, -} from '@masknet/plugin-infra' +import type { Plugin } from '@masknet/plugin-infra' import { ProviderIcon } from './ProviderIcon' import { NetworkIcon } from './NetworkIcon' -import { PluginProviderWatcher } from './PluginProviderWatcher' -import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' const useStyles = makeStyles()((theme) => ({ root: { @@ -76,34 +67,36 @@ const useStyles = makeStyles()((theme) => ({ })) export interface PluginProviderRenderProps { - onClose: () => void + networks: Plugin.Shared.Network[] + providers: Plugin.Shared.Provider[] + undeterminedPluginID: string + undeterminedNetworkID: string + setUndeterminedPluginID: (id: string) => void + setUndeterminedNetworkID: (id: string) => void + NetworkIconClickBait?: React.ComponentType<{ network: Plugin.Shared.Network; children?: React.ReactNode }> + ProviderIconClickBait?: React.ComponentType<{ + network: Plugin.Shared.Network + provider: Plugin.Shared.Provider + children?: React.ReactNode + }> + onSubmit: () => void } -export function PluginProviderRender({ onClose }: PluginProviderRenderProps) { +export function PluginProviderRender({ + networks, + providers, + undeterminedPluginID, + undeterminedNetworkID, + setUndeterminedPluginID, + setUndeterminedNetworkID, + NetworkIconClickBait, + ProviderIconClickBait, + onSubmit, +}: PluginProviderRenderProps) { const { classes } = useStyles() - const networks = useRegisteredNetworks() - const providers = useRegisteredProviders() - - const pluginID = useValueRef(pluginIDSettings) - const networkID = useValueRef(networkIDSettings) - const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) - const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) - - const pluginSNSAdaptor = useActivatedPluginSNSAdaptor(undeterminedPluginID) - const pluginDashboard = useActivatedPluginDashboard(undeterminedPluginID) - - const { useNetwork, useProvider, NetworkIconClickBait, ProviderIconClickBait } = - (pluginSNSAdaptor ?? pluginDashboard)?.Web3Provider?.SelectProviderDialog ?? {} - return ( <> -
    @@ -138,7 +131,7 @@ export function PluginProviderRender({ onClose }: PluginProviderRenderProps) { 2. Choose Wallet - + {providers .filter((x) => x.pluginID === undeterminedPluginID) .map((provider) => ( diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx deleted file mode 100644 index 930c17f19095..000000000000 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderWatcher.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { Plugin } from '@masknet/plugin-infra' -import { useRef } from 'react' - -export interface PluginProviderWatcherProps { - useNetwork?: () => Plugin.Shared.Network | null - useProvider?: () => Plugin.Shared.Provider | null - expectedPluginID: string - expectedNetworkID: string -} - -export function PluginProviderWatcher({ useNetwork, useProvider }: PluginProviderWatcherProps) { - const network = useRef<() => Plugin.Shared.Network | null>(useNetwork ?? (() => null)).current() - const provider = useRef<() => Plugin.Shared.Provider | null>(useProvider ?? (() => null)).current() - - console.log('DEBUG: PluginProviderWatcher') - console.log({ - network, - provider, - }) - - return null -} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index f91e111af9f2..8ab5bfcf3865 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,12 +1,20 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { makeStyles } from '@masknet/theme' import { DialogContent } from '@mui/material' -import { useRemoteControlledDialog } from '@masknet/shared' +import { useRemoteControlledDialog, useValueRef } from '@masknet/shared' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' +import { PluginNetworkWatcher } from './PluginNetworkWatcher' +import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' +import { + useActivatedPluginSNSAdaptor, + useActivatedPluginDashboard, + useRegisteredNetworks, + useRegisteredProviders, +} from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ content: { @@ -18,9 +26,9 @@ const useStyles = makeStyles()((theme) => ({ }, })) -interface SelectProviderDialogUIProps extends withClasses {} +export interface SelectProviderDialogProps {} -function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { +export function SelectProviderDialog(props: SelectProviderDialogProps) { const { t } = useI18N() const { classes } = useStyles() @@ -35,20 +43,48 @@ function SelectProviderDialogUI(props: SelectProviderDialogUIProps) { }, [open]) //#endregion + const pluginID = useValueRef(pluginIDSettings) + const networkID = useValueRef(networkIDSettings) + const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) + const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) + + const networks = useRegisteredNetworks() + const providers = useRegisteredProviders() + + const pluginSNSAdaptor = useActivatedPluginSNSAdaptor(undeterminedPluginID) + const pluginDashboard = useActivatedPluginDashboard(undeterminedPluginID) + + const { useNetwork, NetworkIconClickBait, ProviderIconClickBait } = + (pluginSNSAdaptor ?? pluginDashboard)?.Web3Provider?.SelectProviderDialog ?? {} + // not available for the native app if (hasNativeAPI) return null + // if the dialog closes then start capturing the currently selected network + if (!open) + return ( + null)} + expectedPluginID={undeterminedPluginID} + expectedNetworkID={undeterminedNetworkID} + /> + ) + return ( - + ) } - -export interface SelectProviderDialogProps extends SelectProviderDialogUIProps {} - -export function SelectProviderDialog(props: SelectProviderDialogProps) { - return -} diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index 4496ebe72ff9..3b5c7163909c 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -26,26 +26,12 @@ export function useRegisteredPlugins() { export function useRegisteredNetworks() { const plugins = useRegisteredPlugins() - return useMemo(() => { - return plugins.flatMap((x) => - (x.networks ?? []).map((y) => ({ - ...y, - pluginID: x.ID, - })), - ) - }, [plugins.map((x) => x.ID).join()]) + return useMemo(() => plugins.flatMap((x) => x.networks ?? []), [plugins.map((x) => x.ID).join()]) } export function useRegisteredProviders() { const plugins = useRegisteredPlugins() - return useMemo(() => { - return plugins.flatMap((x) => - (x.providers ?? []).map((y) => ({ - ...y, - pluginID: x.ID, - })), - ) - }, [plugins.map((x) => x.ID).join()]) + return useMemo(() => plugins.flatMap((x) => x.providers ?? []), [plugins.map((x) => x.ID).join()]) } function __meetRegisterRequirement(def: Plugin.Shared.Definition) { diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index b543aea79dc3..b72e35bf076a 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -175,6 +175,8 @@ export namespace Plugin.Shared { export interface Network { /** An unique ID for each network */ ID: string + /** The plugin ID */ + pluginID: string /** The network type */ type: string /** The network icon */ @@ -186,6 +188,8 @@ export namespace Plugin.Shared { export interface Provider { /** An unique ID for each wallet provider */ ID: string + /** The plugin ID */ + pluginID: string /** The provider type */ type: string /** The provider icon */ diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts index ea81744e1291..31c3ed9b430c 100644 --- a/packages/plugins/Flow/src/constants.ts +++ b/packages/plugins/Flow/src/constants.ts @@ -9,6 +9,7 @@ export const PLUGIN_DESCRIPTION = '' export const PLUGIN_NETWORKS: Plugin.Shared.Network[] = [ { ID: `${PLUGIN_ID}_flow`, + pluginID: PLUGIN_ID, type: NetworkType.Flow, name: 'Flow', icon: new URL('./assets/flow.png', import.meta.url).toString(), @@ -17,6 +18,7 @@ export const PLUGIN_NETWORKS: Plugin.Shared.Network[] = [ export const PLUGIN_PROVIDERS: Plugin.Shared.Provider[] = [ { ID: `${PLUGIN_ID}_blocto`, + pluginID: PLUGIN_ID, type: ProviderType.Blocto, name: 'Blocto', icon: new URL('./assets/blocto.png', import.meta.url).toString(), From 015ca16d06b0280eb6ad4fc828d79abf4fc7a8bb Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sat, 6 Nov 2021 16:34:06 +0800 Subject: [PATCH 07/41] fix: typo --- cspell.json | 5 ++++- packages/plugin-infra/src/types.ts | 4 ++-- packages/plugins/Flow/src/UI/components/PluginPanel.tsx | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cspell.json b/cspell.json index 01d78891ba7c..6170d47b72fb 100644 --- a/cspell.json +++ b/cspell.json @@ -309,7 +309,10 @@ "fbclid", "noamount", "txts", - "redpackets" + "redpackets", + "blocto", + "onflow", + "unauthenticate" ], "ignoreRegExpList": ["/@servie/"], "ignorePaths": [ diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index b72e35bf076a..85fc84f02f14 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -204,9 +204,9 @@ export namespace Plugin.Shared { useProvider?: () => Shared.Provider | null /** A react hook returns the currently selected network. */ useNetwork?: () => Shared.Network | null - /** This UI will receve network icon as children component, and the plugin may hook click handle on it. */ + /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> - /** This UI will receve provider icon as children component, and the plugin may hook click handle on it. */ + /** This UI will receive provider icon as children component, and the plugin may hook click handle on it. */ ProviderIconClickBait?: React.ComponentType<{ network: Shared.Network provider: Shared.Provider diff --git a/packages/plugins/Flow/src/UI/components/PluginPanel.tsx b/packages/plugins/Flow/src/UI/components/PluginPanel.tsx index 24e4f99ea922..aa08abc5ddf1 100644 --- a/packages/plugins/Flow/src/UI/components/PluginPanel.tsx +++ b/packages/plugins/Flow/src/UI/components/PluginPanel.tsx @@ -26,7 +26,7 @@ const useStyles = makeStyles()((theme) => ({ cursor: 'pointer', stroke: theme.palette.text.secondary, }, - lable: { + label: { fontSize: 18, }, balance: { @@ -59,7 +59,7 @@ export function PluginPanel(props: PluginPanelProps) { - + Profile Information From 5db9fa8fcc83d537409535f36f597db20ad86427 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sat, 6 Nov 2021 17:11:44 +0800 Subject: [PATCH 08/41] refactor(ui): wallet icon --- .../components/WalletStateBar/index.tsx | 5 +-- .../InjectedComponents/ToolboxUnstyled.tsx | 9 +++-- .../components/WalletStateBar/index.tsx | 4 +-- .../SNSAdaptor/components/DrawDialog.tsx | 5 +-- .../plugins/PoolTogether/UI/NetworkView.tsx | 4 +-- .../Profile/SNSAdaptor/WalletsPage.tsx | 5 ++- .../ConnectionProgress.tsx | 4 +-- .../PluginProviderRender.tsx | 8 ++--- .../SelectProviderDialog/ProviderIcon.tsx | 2 +- .../SNSAdaptor/WalletStatusDialog/index.tsx | 11 ++++-- packages/plugin-infra/src/manager/manage.ts | 2 -- packages/plugin-infra/src/types.ts | 3 ++ .../src/UI/components/ChainIcon/index.tsx | 6 ++-- .../src/UI/components/ImageIcon/index.tsx} | 8 +++-- .../src/UI/components/NetworkIcon/index.tsx | 34 ------------------ .../wallet-network-icon/arbitrum.png | Bin 35907 -> 0 bytes .../wallet-network-icon/binance.png | Bin 3471 -> 0 bytes .../wallet-network-icon/ethereum.png | Bin 692 -> 0 bytes .../wallet-network-icon/polygon.png | Bin 1841 -> 0 bytes .../NetworkIcon/wallet-network-icon/xdai.png | Bin 707 -> 0 bytes .../src/UI/components/ProviderIcon/index.tsx | 29 --------------- .../src/UI/components/WalletIcon/index.tsx} | 17 ++++----- packages/shared/src/UI/components/index.ts | 6 ++-- .../web3-shared/flow/hooks/useNetworkType.ts | 4 ++- 24 files changed, 56 insertions(+), 110 deletions(-) rename packages/{mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx => shared/src/UI/components/ImageIcon/index.tsx} (62%) delete mode 100644 packages/shared/src/UI/components/NetworkIcon/index.tsx delete mode 100644 packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/arbitrum.png delete mode 100644 packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/binance.png delete mode 100644 packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/ethereum.png delete mode 100644 packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/polygon.png delete mode 100644 packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/xdai.png delete mode 100644 packages/shared/src/UI/components/ProviderIcon/index.tsx rename packages/{mask/src/components/shared/WalletIcon.tsx => shared/src/UI/components/WalletIcon/index.tsx} (50%) diff --git a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx index 97e92c099ca1..2303cb795500 100644 --- a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx @@ -10,7 +10,7 @@ import { useWeb3StateContext, } from '@masknet/web3-shared-evm' import { makeStyles, MaskColorVar } from '@masknet/theme' -import { FormattedAddress, LoadingAnimation, ProviderIcon, useRemoteControlledDialog } from '@masknet/shared' +import { FormattedAddress, LoadingAnimation, ImageIcon, useRemoteControlledDialog } from '@masknet/shared' import { PluginMessages } from '../../../../API' import { useRecentTransactions } from '../../hooks/useRecentTransactions' import { useDashboardI18N } from '../../../../locales' @@ -128,7 +128,8 @@ export const WalletStateBarUI: FC = ({ )} - + {/* */} + {walletName} diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index ba4438fc6e9b..012bff350a85 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -32,7 +32,7 @@ import { MaskMessages } from '../../utils/messages' import { PLUGIN_ID as TransakPluginID } from '../../plugins/Transak/constants' import { PLUGIN_IDENTIFIER as TraderPluginID } from '../../plugins/Trader/constants' import { useControlledDialog } from '../../utils/hooks/useControlledDialog' -import { useRemoteControlledDialog } from '@masknet/shared' +import { useRemoteControlledDialog, WalletIcon } from '@masknet/shared' import { PluginTransakMessages } from '../../plugins/Transak/messages' import { PluginTraderMessages } from '../../plugins/Trader/messages' import { WalletMessages } from '../../plugins/Wallet/messages' @@ -44,7 +44,6 @@ import { safeUnreachable } from '@dimensiondev/kit' import { usePluginI18NField } from '../../plugin-infra/I18NFieldRender' import { useRecentTransactions } from '../../plugins/Wallet/hooks/useRecentTransactions' import GuideStep from '../GuideStep' -import { WalletIcon } from '../shared/WalletIcon' import { MaskIcon, MaskSharpIconOfSize, WalletSharp } from '../../resources/MaskIcon' import { makeStyles } from '@masknet/theme' import classNames from 'classnames' @@ -136,7 +135,11 @@ export function ToolboxHintUnstyled(props: ToolboxHintProps) { - {isWalletValid ? : } + {isWalletValid ? ( + + ) : ( + + )} {mini ? null : ( = memo( )} - + {walletName} diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx index c2cd9b9c5944..24048dac63f2 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx @@ -3,7 +3,7 @@ import BigNumber from 'bignumber.js' import { useContainer } from 'unstated-next' import { makeStyles } from '@masknet/theme' import { Add, Remove } from '@mui/icons-material' -import { FormattedAddress, FormattedBalance, ProviderIcon } from '@masknet/shared' +import { FormattedAddress, FormattedBalance, ImageIcon } from '@masknet/shared' import { Box, Button, DialogContent, TextField, Typography } from '@mui/material' import { formatBalance, @@ -214,7 +214,8 @@ export function DrawDialog(props: DrawDialogProps) { Current Wallet: - + {/* */} + diff --git a/packages/mask/src/plugins/PoolTogether/UI/NetworkView.tsx b/packages/mask/src/plugins/PoolTogether/UI/NetworkView.tsx index 20753fe4c0de..bc21a85ff78e 100644 --- a/packages/mask/src/plugins/PoolTogether/UI/NetworkView.tsx +++ b/packages/mask/src/plugins/PoolTogether/UI/NetworkView.tsx @@ -1,7 +1,7 @@ import { ChainId, getChainDetailed, getNetworkTypeFromChainId } from '@masknet/web3-shared-evm' import { Typography } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { NetworkIcon, useStylesExtends } from '@masknet/shared' +import { ImageIcon, useStylesExtends } from '@masknet/shared' import { getNetworkColor } from '../utils' const useStyles = makeStyles()((theme) => ({ @@ -31,7 +31,7 @@ export const NetworkView = (props: NetworkViewProps) => { return ( - + {chainDetail?.fullName} ) diff --git a/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx b/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx index 84d0eabdc710..a53a33253000 100644 --- a/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx +++ b/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx @@ -1,6 +1,6 @@ import { RewardIcon } from '@masknet/icons' import { WalletMessages } from '@masknet/plugin-wallet' -import { NetworkIcon, useRemoteControlledDialog, useSnackbarCallback } from '@masknet/shared' +import { ImageIcon, useRemoteControlledDialog, useSnackbarCallback } from '@masknet/shared' import { makeStyles } from '@masknet/theme' import { formatEthereumAddress, @@ -55,7 +55,6 @@ export function WalletsPage() { const chainId = useChainId() const { classes } = useStyles() - const chainColor = useChainColor() const { openDialog: openSelectWalletDialog } = useRemoteControlledDialog( WalletMessages.events.walletStatusDialogUpdated, ) @@ -75,7 +74,7 @@ export function WalletsPage() { {wallets.map((wallet, i) => ( - + diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx index d87e3677ebe6..4efb48d6dfaf 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx @@ -3,7 +3,7 @@ import { makeStyles } from '@masknet/theme' import { resolveProviderName, ProviderType } from '@masknet/web3-shared-evm' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { useI18N } from '../../../../utils' -import { ProviderIcon, useStylesExtends } from '@masknet/shared' +import { ImageIcon, useStylesExtends } from '@masknet/shared' import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry' import { getMaskColor } from '@masknet/theme' @@ -36,7 +36,7 @@ export function ConnectionProgress(props: ConnectionProgressProps) { - + {connected ? ( Connected to {resolveProviderName(providerType)} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index 086e3edaf0f7..bc47b3d37a8b 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -1,9 +1,9 @@ import { SuccessIcon } from '@masknet/icons' +import { ImageIcon } from '@masknet/shared' +import type { Plugin } from '@masknet/plugin-infra' import { getMaskColor, makeStyles } from '@masknet/theme' import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' -import type { Plugin } from '@masknet/plugin-infra' import { ProviderIcon } from './ProviderIcon' -import { NetworkIcon } from './NetworkIcon' const useStyles = makeStyles()((theme) => ({ root: { @@ -114,10 +114,10 @@ export function PluginProviderRender({
    {NetworkIconClickBait ? ( - + ) : ( - + )} {undeterminedNetworkID === network.ID && ( diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx index b3d3a58951ee..58e28ff2bf33 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx @@ -12,7 +12,7 @@ const useStyles = makeStyles()((theme) => ({ flexDirection: 'column', alignItems: 'center', justifyContent: 'center', - padding: theme.spacing(4, 1), + // padding: theme.spacing(4, 1), backgroundColor: getMaskColor(theme).twitterBackground, }, icon: { diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx index 9d2e41e36fd6..5c940d2126ed 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx @@ -1,4 +1,10 @@ -import { FormattedAddress, useRemoteControlledDialog, useValueRef, useSnackbarCallback } from '@masknet/shared' +import { + WalletIcon, + FormattedAddress, + useRemoteControlledDialog, + useValueRef, + useSnackbarCallback, +} from '@masknet/shared' import { ProviderType, resolveAddressLinkOnExplorer, @@ -14,7 +20,6 @@ import { useCallback } from 'react' import { Copy, Edit3, ExternalLink } from 'react-feather' import { useCopyToClipboard } from 'react-use' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' -import { WalletIcon } from '../../../../components/shared/WalletIcon' import Services from '../../../../extension/service' import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' @@ -150,7 +155,7 @@ export function WalletStatusDialog(props: WalletStatusDialogProps) {
    - +
    {selectedWallet.name} diff --git a/packages/plugin-infra/src/manager/manage.ts b/packages/plugin-infra/src/manager/manage.ts index 8bf69b26b290..63053c241766 100644 --- a/packages/plugin-infra/src/manager/manage.ts +++ b/packages/plugin-infra/src/manager/manage.ts @@ -52,8 +52,6 @@ export function createManager + } SelectProviderDialog?: { /** A react hook returns the currently selected provider. */ useProvider?: () => Shared.Provider | null diff --git a/packages/shared/src/UI/components/ChainIcon/index.tsx b/packages/shared/src/UI/components/ChainIcon/index.tsx index 34c23872424b..f60e97f9e413 100644 --- a/packages/shared/src/UI/components/ChainIcon/index.tsx +++ b/packages/shared/src/UI/components/ChainIcon/index.tsx @@ -1,7 +1,7 @@ import { memo } from 'react' -import { ChainId, getChainDetailed, getNetworkTypeFromChainId, resolveChainColor } from '@masknet/web3-shared-evm' +import { ChainId, getChainDetailed, resolveChainColor } from '@masknet/web3-shared-evm' import { makeStyles } from '@masknet/theme' -import { NetworkIcon } from '../NetworkIcon' +import { ImageIcon } from '../ImageIcon' const useStyles = makeStyles()({ point: { @@ -21,7 +21,7 @@ export const ChainIcon = memo(({ chainId, size }) => { const chainDetail = getChainDetailed(chainId) return chainDetail?.network === 'mainnet' ? ( - + ) : (
    ) diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx b/packages/shared/src/UI/components/ImageIcon/index.tsx similarity index 62% rename from packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx rename to packages/shared/src/UI/components/ImageIcon/index.tsx index 8731ed6198d2..217749d104aa 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/NetworkIcon.tsx +++ b/packages/shared/src/UI/components/ImageIcon/index.tsx @@ -1,4 +1,5 @@ import { makeStyles } from '@masknet/theme' +import { useStylesExtends } from '../..' const useStyles = makeStyles()((theme) => { return { @@ -11,12 +12,13 @@ const useStyles = makeStyles()((theme) => { } }) -export interface NetworkIconProps { +export interface ImageIconProps extends withClasses<'icon'> { size?: number icon: string } -export function NetworkIcon({ size = 48, icon }: NetworkIconProps) { - const { classes } = useStyles() +export function ImageIcon(props: ImageIconProps) { + const { size = 48, icon } = props + const classes = useStylesExtends(useStyles(), props) return } diff --git a/packages/shared/src/UI/components/NetworkIcon/index.tsx b/packages/shared/src/UI/components/NetworkIcon/index.tsx deleted file mode 100644 index 2189f3679c62..000000000000 --- a/packages/shared/src/UI/components/NetworkIcon/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { makeStyles } from '@masknet/theme' -import { NetworkType } from '@masknet/web3-shared-evm' -import { useStylesExtends } from '../..' - -const useStyles = makeStyles()({ - icon: { - borderRadius: '50%', - backgroundColor: '#F7F9FA', - }, -}) - -export interface NetworkIconProps extends withClasses<'icon'> { - size?: number - networkType?: NetworkType -} - -const icons: Record = { - [NetworkType.Ethereum]: new URL('./wallet-network-icon/ethereum.png', import.meta.url).toString(), - [NetworkType.Binance]: new URL('./wallet-network-icon/binance.png', import.meta.url).toString(), - [NetworkType.Polygon]: new URL('./wallet-network-icon/polygon.png', import.meta.url).toString(), - [NetworkType.Arbitrum]: new URL('./wallet-network-icon/arbitrum.png', import.meta.url).toString(), - [NetworkType.xDai]: new URL('./wallet-network-icon/xdai.png', import.meta.url).toString(), -} - -export function NetworkIcon(props: NetworkIconProps) { - const { size = 48, networkType } = props - const classes = useStylesExtends(useStyles(), props) - - if (!networkType) return null - - return icons[networkType] ? ( - - ) : null -} diff --git a/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/arbitrum.png b/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/arbitrum.png deleted file mode 100644 index 9acea4e36db9e5b8c9c6da9693fc5fa41dedfaf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35907 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 diff --git a/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/ethereum.png b/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/ethereum.png deleted file mode 100644 index 44ff0159cfe4ddbad1671c32d92117d56b3ab968..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!|1AIbUfwV_NhDSsikPHYY@Q6qU zqg0OwAWHL$OmhzhN&y)_E>H^0jm-3jNb!hF3rI-tib{142ck5us4RD&;>a|&Fpw_K z@O00}6wmNfuc&m-aF8ybplehrkOUf{U9e6SXt7#JkY6x^!hHvU`TG<0H@q*Xe}8|$ z`*??Vf&2;Q4c7Mute;RYA-}&rz~Fqv=Z!iH42&l{T^vIy;@)1rnfKU$hczH*Q%Ys$ z>2`(D~Sb7WcP6ts+g#i~`SwB$UeH>>*U7O1-BFz~Em zWVG0n@t90CDj@KS8{=ogIhZtw4pH#Gp+?Ba~mZRQ+x&lR%tyX~l;aQ@?u!nf?7CkJ<4`g&7B{{6Lm4~`v` zPY=GqBfeX7S4E1C&nnp!0jJc`WhV2yo_KPS*4FcB(?e!{Yxr*vo5@}yi)3PA@oy>dnWlF{mEOZh`>RKH@6TB=xydly@RQYfR(svpXXp+IoeUi)gJD$AUke!x_~ N;OXk;vd$@?2>`2$Ba;9C diff --git a/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/polygon.png b/packages/shared/src/UI/components/NetworkIcon/wallet-network-icon/polygon.png deleted file mode 100644 index 0fddac404762ff7cfb88a99a5bb85cb797a23ff2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1841 zcmV-12hRA3P)w z?w)V%x#w?2VK5jB27|$1Fc=I5gTY`h7z_r3!C){Lj293IO`I}S>s%sYwIo!l)l}{C zceK@z!U!HPb|Z{_15AP$a2vl%f}i8(`Y~;_LSgt1U0bb!k=qigJq<&r!R>wA1i!}0 zP{(*R_y@f+RRN>7!?;tsSNtK&fb(W#^=*Ywtgp8k6A}A14EhM%0Jl9b2@Ya!2rCSE zm^-efHKB@r7;qijE|TluG!>-8zZI&?NI1KX?+>$Wj7WfRgz!3I`E*#s5|4)ER^mobQ ze+BQE(Ul8Ixni_KoQCoGobYj5mWG=C1S=+#Crk~Q5iyC^{N>?%DeyMVSE-Z}4Al;FmhNTOKvt)i-dS4dH!|e4&7J{FDc~$T=^IA#eb17&Y$2sjIWwn zy4st_)=h9;YK3WH+Ki?fm2v^qZ@?}0t6n?+qhQSuGv^9JvuYqhH#p-ifRzLnlL%c$@b7i1FR=i{31A}(y_txLuuIYyx)ZV5@Y-1? zi{1n?PAF|s@sI^Lf&h50uk;Sla7dl%G>U}ZAJ&6FNo9luIQ)HYfonTgvbgS65=ZWE z6^0-8SnPYew>8QF?1K@pD6tziv~-7hm5TU2k1;~Qm!X2Cp zaJ;1gS7Zy^P2cW#iv+XI>KH}H+D83|M0B~v#72(a&4IQDA!exjO<^y6&r+-fEheJY zt4aW%^U{b5IOoC7Z-TQ}nY}vlfdc)9L8@VaS?T>j!!c3O01-} zmXH8?Tk3?-K|WIqNiJ1l*4gMj9gT@_9#>Os?9_VhgMUk&lg3*n&~tt(sPT5J+-7n$ zB_)6(!bw~q;k`XuNiKtT6XcezDccQLD*$ zk1H%dp1Ms!v+EE^3`vKTppn~*$(W?&V)h3$t->`8ApReq zO`BYbL=7sw`^8y+08okoV4S6zvU3)|T>vT#cL$VUo~68o1#lApM94cEi~v>#-L=C4 zxC=ncnz=n?wcd}hcq$HJfBM*|W|%WW>vOM(dC0Qq81D*`nqkAu5wIA+l)iSq+P4&Kfxny58uMnuZ* z*-%r2FmtpYpRKI~BE%^ByYDT9N27|$1Fc=I5gTY`h7z_r3!C){L f3VHq)`CCc!?6hg{@*y8Q6)u2U@Eetq-&5rE~9K&42Kk zjkjh!D41}8gnjMG?l*oJpEON;z24@Xv~rGa^*XEnEL+z8{C@s(|E$}yDlXdp_u0Sp z=f~;4KmWg@|GFX?Y`ZtdU7w7{P>0;AfV##k4(hI6ai|NiD0y+cB0Qc${axSv$6Kdg znE#9WVMyQkIH!91^{==e9=ZGR_2;|pFP>ILih>n|pHF39IQ@B1Je2#oE%wji@T=m7 zI(I+5%J=UgXXpJ$3kMv*fis-YB+kjWK3%`*7yFmf^M8uok^IK=IBy*)FsaRn!X${*(M&p4Kd%J<8I)Ofo3xvX { - size?: number - providerType?: ProviderType -} - -export function ProviderIcon(props: ProviderIconProps) { - const { size = 40, providerType } = props - const classes = useStylesExtends(useStyles(), props) - - switch (providerType) { - case ProviderType.MaskWallet: - return - case ProviderType.MetaMask: - return - case ProviderType.WalletConnect: - return - default: - return null - } -} diff --git a/packages/mask/src/components/shared/WalletIcon.tsx b/packages/shared/src/UI/components/WalletIcon/index.tsx similarity index 50% rename from packages/mask/src/components/shared/WalletIcon.tsx rename to packages/shared/src/UI/components/WalletIcon/index.tsx index 004ef96bb6a8..9ee3e4bccb06 100644 --- a/packages/mask/src/components/shared/WalletIcon.tsx +++ b/packages/shared/src/UI/components/WalletIcon/index.tsx @@ -1,6 +1,5 @@ -import { NetworkIcon, ProviderIcon, useValueRef } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { currentNetworkSettings, currentProviderSettings } from '../../plugins/Wallet/settings' +import { ImageIcon } from '..' const useStyles = makeStyles()({ root: { @@ -23,12 +22,12 @@ const useStyles = makeStyles()({ interface WalletIconProps { size?: number badgeSize?: number + networkIcon: string + providerIcon: string } -export const WalletIcon = ({ size = 24, badgeSize = 14 }: WalletIconProps) => { +export const WalletIcon = ({ size = 24, badgeSize = 14, networkIcon, providerIcon }: WalletIconProps) => { const { classes } = useStyles() - const selectedNetwork = useValueRef(currentNetworkSettings) - const selectedWalletProvider = useValueRef(currentProviderSettings) return (
    { height: size, width: size, }}> - - + +
    ) } diff --git a/packages/shared/src/UI/components/index.ts b/packages/shared/src/UI/components/index.ts index 7d6b243ee4b4..e4dd3323685d 100644 --- a/packages/shared/src/UI/components/index.ts +++ b/packages/shared/src/UI/components/index.ts @@ -1,11 +1,11 @@ export * from './TokenIcon' +export * from './ChainIcon' +export * from './ImageIcon' +export * from './WalletIcon' export * from './ERC20TokenList' export * from './QRCode' export * from './ErrorBoundary' -export * from './ProviderIcon' export * from './SelectTokenChip' export * from './TokenAmountPanel' -export * from './NetworkIcon' -export * from './ChainIcon' export * from './LoadingAnimation' export * from './MiniNetworkSelector' diff --git a/packages/web3-shared/flow/hooks/useNetworkType.ts b/packages/web3-shared/flow/hooks/useNetworkType.ts index da471cc6db1f..f35d3fc0e1c9 100644 --- a/packages/web3-shared/flow/hooks/useNetworkType.ts +++ b/packages/web3-shared/flow/hooks/useNetworkType.ts @@ -1,5 +1,7 @@ +import { useCurrentUser } from '.' import { NetworkType } from '../types' export function useNetworkType() { - return NetworkType.Flow + const currentUser = useCurrentUser() + return currentUser ? NetworkType.Flow : null } From a29f010cfb5702c50f4f510d10dd505595b60668 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sat, 6 Nov 2021 23:24:51 +0800 Subject: [PATCH 09/41] refactor: move hooks --- packages/dashboard/tsconfig.json | 3 +- .../src/plugins/EVM/UI/Dashboard/index.tsx | 4 +-- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 4 +-- .../index.tsx | 6 ++-- .../SelectProviderDialog/ProviderIcon.tsx | 2 +- .../SNSAdaptor/SelectProviderDialog/index.tsx | 17 +++------- packages/plugin-infra/src/hooks/index.ts | 6 ++++ .../src/hooks/useActivatedPlugin.ts | 7 +++++ .../src/hooks/useRegisteredPlugin.ts | 6 ++++ .../src/hooks/useRegisteredPluginNetwork.ts | 5 +++ .../src/hooks/useRegisteredPluginProvider.ts | 5 +++ .../src/hooks/useWeb3ContextProvider.ts | 6 ++++ .../src/hooks/useWeb3UIProvider.ts | 6 ++++ packages/plugin-infra/src/index.ts | 1 + packages/plugin-infra/src/types.ts | 31 ++++++++++++++----- .../plugins/Flow/src/UI/Dashboard/index.tsx | 4 +-- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 4 +-- .../index.tsx | 6 ++-- 18 files changed, 90 insertions(+), 33 deletions(-) rename packages/mask/src/plugins/EVM/UI/{Web3Provider => Web3UIProvider}/index.tsx (77%) create mode 100644 packages/plugin-infra/src/hooks/index.ts create mode 100644 packages/plugin-infra/src/hooks/useActivatedPlugin.ts create mode 100644 packages/plugin-infra/src/hooks/useRegisteredPlugin.ts create mode 100644 packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts create mode 100644 packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts create mode 100644 packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts create mode 100644 packages/plugin-infra/src/hooks/useWeb3UIProvider.ts rename packages/plugins/Flow/src/UI/{Web3Provider => Web3UIProvider}/index.tsx (88%) diff --git a/packages/dashboard/tsconfig.json b/packages/dashboard/tsconfig.json index 892aa214ca71..8aacbdcccd83 100644 --- a/packages/dashboard/tsconfig.json +++ b/packages/dashboard/tsconfig.json @@ -11,10 +11,11 @@ { "path": "../theme/" }, { "path": "../mask/src" }, { "path": "../web3-shared/evm/" }, + { "path": "../web3-shared/flow/" }, { "path": "../icons/" }, { "path": "../plugin-infra" }, - { "path": "../plugins/Wallet/" }, { "path": "../plugins/Flow/" }, + { "path": "../plugins/Wallet/" }, { "path": "../backup-format/" } ] } diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index b6f78e11befb..50e206f88c3d 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3Provider } from '../Web3Provider' +import { Web3UIProvider } from '../Web3UIProvider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3Provider, + Web3UIProvider, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index b6f78e11befb..50e206f88c3d 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3Provider } from '../Web3Provider' +import { Web3UIProvider } from '../Web3UIProvider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3Provider, + Web3UIProvider, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx similarity index 77% rename from packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx rename to packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx index 858a8431d1c3..a8ec08d4ac30 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3Provider/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx @@ -2,10 +2,12 @@ import type { Plugin } from '@masknet/plugin-infra' import { useNetwork, useProvider } from '../../hooks' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3Provider: Plugin.Shared.Web3Provider = { - SelectProviderDialog: { +export const Web3UIProvider: Plugin.Shared.Web3UIProvider = { + Shared: { useNetwork, useProvider, + }, + SelectProviderDialog: { ProviderIconClickBait, }, } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx index 58e28ff2bf33..b3d3a58951ee 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx @@ -12,7 +12,7 @@ const useStyles = makeStyles()((theme) => ({ flexDirection: 'column', alignItems: 'center', justifyContent: 'center', - // padding: theme.spacing(4, 1), + padding: theme.spacing(4, 1), backgroundColor: getMaskColor(theme).twitterBackground, }, icon: { diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 8ab5bfcf3865..03ff7bf63bd6 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -9,12 +9,7 @@ import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' -import { - useActivatedPluginSNSAdaptor, - useActivatedPluginDashboard, - useRegisteredNetworks, - useRegisteredProviders, -} from '@masknet/plugin-infra' +import { useRegisteredNetworks, useRegisteredProviders, useWeb3UIProvider } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ content: { @@ -51,11 +46,9 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const pluginSNSAdaptor = useActivatedPluginSNSAdaptor(undeterminedPluginID) - const pluginDashboard = useActivatedPluginDashboard(undeterminedPluginID) - - const { useNetwork, NetworkIconClickBait, ProviderIconClickBait } = - (pluginSNSAdaptor ?? pluginDashboard)?.Web3Provider?.SelectProviderDialog ?? {} + const Web3UIProvider = useWeb3UIProvider(pluginID) + const { useNetwork = () => null } = Web3UIProvider?.Shared ?? {} + const { NetworkIconClickBait, ProviderIconClickBait } = Web3UIProvider?.SelectProviderDialog ?? {} // not available for the native app if (hasNativeAPI) return null @@ -64,7 +57,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { if (!open) return ( null)} + useNetwork={useNetwork} expectedPluginID={undeterminedPluginID} expectedNetworkID={undeterminedNetworkID} /> diff --git a/packages/plugin-infra/src/hooks/index.ts b/packages/plugin-infra/src/hooks/index.ts new file mode 100644 index 000000000000..a19017fdde9d --- /dev/null +++ b/packages/plugin-infra/src/hooks/index.ts @@ -0,0 +1,6 @@ +export * from './useActivatedPlugin' +export * from './useRegisteredPlugin' +export * from './useRegisteredPluginNetwork' +export * from './useRegisteredPluginProvider' +export * from './useWeb3UIProvider' +export * from './useWeb3ContextProvider' diff --git a/packages/plugin-infra/src/hooks/useActivatedPlugin.ts b/packages/plugin-infra/src/hooks/useActivatedPlugin.ts new file mode 100644 index 000000000000..fc0c34cfbd54 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useActivatedPlugin.ts @@ -0,0 +1,7 @@ +import { useActivatedPluginDashboard, useActivatedPluginSNSAdaptor } from '..' + +export function useActivatedPlugin(pluginID: string) { + const pluginSNSAdaptor = useActivatedPluginSNSAdaptor(pluginID) + const pluginDashboard = useActivatedPluginDashboard(pluginID) + return pluginSNSAdaptor ?? pluginDashboard ?? null +} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts b/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts new file mode 100644 index 000000000000..c56719b5341b --- /dev/null +++ b/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts @@ -0,0 +1,6 @@ +import { useRegisteredPlugins } from '../manager/store' + +export function useRegisteredPlugin(pluginID: string) { + const plugins = useRegisteredPlugins() + return plugins.find((x) => x.ID === pluginID) +} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts new file mode 100644 index 000000000000..51b945243192 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts @@ -0,0 +1,5 @@ +import { useRegisteredPlugin } from './' + +export function useRegisteredPluginNetwork(pluginID: string, networkID: string) { + return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.ID === networkID) +} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts new file mode 100644 index 000000000000..8c4a636c6cda --- /dev/null +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts @@ -0,0 +1,5 @@ +import { useRegisteredPlugin } from './' + +export function useRegisteredPluginProvider(pluginID: string, providerID: string) { + return useRegisteredPlugin(pluginID)?.providers?.find((x) => x.ID === providerID) +} diff --git a/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts b/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts new file mode 100644 index 000000000000..fc0c121e9931 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts @@ -0,0 +1,6 @@ +import { useActivatedPlugin } from './useActivatedPlugin' + +export function useWeb3ContextProvider(pluginID: string) { + const activatedPlugin = useActivatedPlugin(pluginID) + return activatedPlugin?.Web3ContextProvider ?? null +} diff --git a/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts b/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts new file mode 100644 index 000000000000..945f1e03f71d --- /dev/null +++ b/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts @@ -0,0 +1,6 @@ +import { useActivatedPlugin } from './useActivatedPlugin' + +export function useWeb3UIProvider(pluginID: string) { + const activatedPlugin = useActivatedPlugin(pluginID) + return activatedPlugin?.Web3UIProvider ?? null +} diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index c66ebffb5cda..59005fd6b0f8 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -3,6 +3,7 @@ export * from './manager/dashboard' export * from './manager/sns-adaptor' export * from './manager/worker' export * from './utils' +export * from './hooks' export * from './PostContext' export * from 'ts-results' export { diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 5e97d626bff2..08e375df3968 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -3,6 +3,7 @@ import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' import type { ChainId } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' +import type { Subscription } from 'use-subscription' export namespace Plugin { /** @@ -198,15 +199,14 @@ export namespace Plugin.Shared { name: string } - export interface Web3Provider { + export interface Web3UIProvider { Shared?: { - WalletIcon: React.ComponentType<{ size?: number; badgeSize?: number }> - } - SelectProviderDialog?: { /** A react hook returns the currently selected provider. */ useProvider?: () => Shared.Provider | null /** A react hook returns the currently selected network. */ useNetwork?: () => Shared.Network | null + } + SelectProviderDialog?: { /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> /** This UI will receive provider icon as children component, and the plugin may hook click handle on it. */ @@ -224,6 +224,20 @@ export namespace Plugin.Shared { HistoryTableComponent?: React.ComponentType<{}> } } + + export interface ContextProvider { + allowTestnet: Subscription + chainId: Subscription + account: Subscription + balance: Subscription + blockNumber: Subscription + networkType: Subscription + providerType: Subscription + } + + export interface Web3ContextProvider { + Context?: ContextProvider + } } /** This part runs in the SNSAdaptor */ @@ -238,7 +252,9 @@ export namespace Plugin.SNSAdaptor { /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3Provider?: Shared.Web3Provider + Web3UIProvider?: Shared.Web3UIProvider + /** This is the web3 context. */ + Web3ContextProvider?: Shared.Web3ContextProvider /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -329,9 +345,10 @@ export namespace Plugin.Dashboard { export interface Definition extends Shared.DefinitionDeferred { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> - /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3Provider?: Shared.Web3Provider + Web3UIProvider?: Shared.Web3UIProvider + /** This is the web3 context. */ + Web3ContextProvider?: Shared.Web3ContextProvider } } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index e581ac9e82ff..590c21f9a4ec 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' -import { Web3Provider } from '../Web3Provider' +import { Web3UIProvider } from '../Web3UIProvider' const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, - Web3Provider, + Web3UIProvider, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index b6f78e11befb..50e206f88c3d 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3Provider } from '../Web3Provider' +import { Web3UIProvider } from '../Web3UIProvider' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3Provider, + Web3UIProvider, } export default sns diff --git a/packages/plugins/Flow/src/UI/Web3Provider/index.tsx b/packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx similarity index 88% rename from packages/plugins/Flow/src/UI/Web3Provider/index.tsx rename to packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx index 0445993c28b9..f26434d9ba2d 100644 --- a/packages/plugins/Flow/src/UI/Web3Provider/index.tsx +++ b/packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx @@ -3,8 +3,8 @@ import { useNetworkType, useProviderType } from '@masknet/web3-shared-flow' import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3Provider: Plugin.Shared.Web3Provider = { - SelectProviderDialog: { +export const Web3UIProvider: Plugin.Shared.Web3UIProvider = { + Shared: { useNetwork() { const networkType = useNetworkType() return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null @@ -13,6 +13,8 @@ export const Web3Provider: Plugin.Shared.Web3Provider = { const providerType = useProviderType() return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null }, + }, + SelectProviderDialog: { ProviderIconClickBait, }, } From 98ca88b056c5388b3d5118af6c7f584aa41a6664 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Sun, 7 Nov 2021 23:48:48 +0800 Subject: [PATCH 10/41] refactor: Web3ContextProvider (wip) --- packages/plugin-infra/src/types.ts | 44 +++++++++++++++++++----- packages/web3-shared/evm/context/type.ts | 13 +++---- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 08e375df3968..b40c6ed79b48 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -225,18 +225,44 @@ export namespace Plugin.Shared { } } - export interface ContextProvider { - allowTestnet: Subscription - chainId: Subscription - account: Subscription - balance: Subscription - blockNumber: Subscription - networkType: Subscription - providerType: Subscription + export interface CryptoPrice { + [token: string]: { + [currency: string]: number + } } + export interface Wallet { + /** User define wallet name. Default address.prefix(6) */ + name: string + /** The address of wallet */ + address: string + /** yep: Mask Wallet, nope: External Wallet */ + hasStoredKeyInfo: boolean + /** yep: Derivable Wallet. nope: UnDerivable Wallet */ + hasDerivationPath: boolean + } export interface Web3ContextProvider { - Context?: ContextProvider + Shared?: { + allowTestnet: Subscription + /** The ID of currently choosed sub-network. */ + chainId: Subscription + /** The address of the currently choosed wallet. */ + account: Subscription + /** The balance of the currently choose account. */ + balance: Subscription + /** The currently tracked block height. */ + blockNumber: Subscription + /** The network type. */ + networkType: Subscription + /** The wallet provider type. */ + providerType: Subscription + /** The tracked token prices which stored as address and price pairs. */ + tokenPrices: Subscription + /** The currently stored wallet by MaskWallet. */ + wallets: Subscription + /** The default derivable wallet. */ + walletPrimary: Subscription + } } } diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index a5d730003d2a..7a6065978d79 100644 --- a/packages/web3-shared/evm/context/type.ts +++ b/packages/web3-shared/evm/context/type.ts @@ -19,17 +19,18 @@ import type { } from '../types' export interface Web3ProviderType { - provider: Subscription allowTestnet: Subscription - account: Subscription - tokenPrices: Subscription chainId: Subscription + account: Subscription balance: Subscription blockNumber: Subscription - walletPrimary: Subscription - wallets: Subscription - providerType: Subscription + provider: Subscription networkType: Subscription + providerType: Subscription + tokenPrices: Subscription + wallets: Subscription + walletPrimary: Subscription + erc20Tokens: Subscription erc721Tokens: Subscription erc1155Tokens: Subscription From 5eeb1d765f02b8ddeba34e1b0dd2c21c2124bcca Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 10:15:52 +0800 Subject: [PATCH 11/41] fix: ts error --- .../mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx b/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx index a53a33253000..a3de9903094f 100644 --- a/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx +++ b/packages/mask/src/plugins/Profile/SNSAdaptor/WalletsPage.tsx @@ -2,14 +2,7 @@ import { RewardIcon } from '@masknet/icons' import { WalletMessages } from '@masknet/plugin-wallet' import { ImageIcon, useRemoteControlledDialog, useSnackbarCallback } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { - formatEthereumAddress, - getNetworkTypeFromChainId, - resolveAddressLinkOnExplorer, - useChainColor, - useChainId, - useWallets, -} from '@masknet/web3-shared-evm' +import { formatEthereumAddress, resolveAddressLinkOnExplorer, useChainId, useWallets } from '@masknet/web3-shared-evm' import { Button, Link, List, ListItem, ListItemIcon, ListItemText, Typography } from '@mui/material' import { useMemo } from 'react' import { Trans } from 'react-i18next' From a6acba14048c6579ccf8c67d7aebcca26fda4c69 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 13:51:03 +0800 Subject: [PATCH 12/41] refactor: plugin types a high level type definition of web3contextprovider --- packages/mask/src/web3/context.ts | 1 - packages/plugin-infra/src/types.ts | 160 ++++++++++++++++++++++- packages/web3-shared/evm/context/type.ts | 1 - 3 files changed, 153 insertions(+), 9 deletions(-) diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 7a881f451069..4b9405322db5 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -95,7 +95,6 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy getAddressNamesList: WalletRPC.getAddressNames, fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, getTransactionList: WalletRPC.getTransactionList, - createMnemonicWords: WalletRPC.createMnemonicWords, } } diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index b40c6ed79b48..f2fab5d907b9 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -1,7 +1,7 @@ import type React from 'react' import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' -import type { ChainId } from '@masknet/web3-shared-evm' +import type { ChainId, NonFungibleToken } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' import type { Subscription } from 'use-subscription' @@ -225,9 +225,20 @@ export namespace Plugin.Shared { } } + export enum CurrencyType { + NATIVE = 'native', + BTC = 'btc', + USD = 'usd', + } + + export enum TokenType { + Fungible = 'Fungible', + NonFungible = 'NonFungible', + } + export interface CryptoPrice { [token: string]: { - [currency: string]: number + [key in CurrencyType]: number } } @@ -241,14 +252,92 @@ export namespace Plugin.Shared { /** yep: Derivable Wallet. nope: UnDerivable Wallet */ hasDerivationPath: boolean } + + export interface Pagination { + /** The item size of each page. */ + size?: number + /** The page index. */ + page?: number + } + + export interface Asset { + id: string + chain: string + balance: string + token: Token + /** estimated price */ + price?: { + [key in CurrencyType]: string + } + /** estimated value */ + value?: { + [key in CurrencyType]: string + } + logoURI?: string + } + + export interface AddressName { + id: string + /** eg. vitalik.eth */ + label: string + /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ + ownerAddress: string + /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ + resolvedAddress?: string + } + + export interface Transaction { + id: string + type: string + title: string + from: string + to: string + timestamp: string + /** 0: failed 1: succeed */ + status: 0 | 1 + /** estimated tx fee */ + fee: { + [key in CurrencyType]: string + } + } + + export interface Token { + id: string + type: TokenType + token: T + } + + export interface FungibleTokenMetadata { + name: string + symbol: string + decimals: number + iconURL?: string + _token: T + } + + export interface NonFungibleTokenMetadata { + name: string + description: string + mediaType: string + iconURL?: string + assetURL?: string + _token: T + } + + export interface TokenList { + name: string + description?: string + tokens: Token[] + } + export interface Web3ContextProvider { Shared?: { allowTestnet: Subscription - /** The ID of currently choosed sub-network. */ + /** The ID of currently choosen sub-network. */ chainId: Subscription - /** The address of the currently choosed wallet. */ + /** The address of the currently choosen wallet. */ account: Subscription - /** The balance of the currently choose account. */ + /** The balance of the currently choosen account. */ balance: Subscription /** The currently tracked block height. */ blockNumber: Subscription @@ -256,6 +345,14 @@ export namespace Plugin.Shared { networkType: Subscription /** The wallet provider type. */ providerType: Subscription + /** The asset data provider. */ + assetType: Subscription + /** The address name data provider. */ + nameType: Subscription + /** The collectible data provider. */ + collectibleType: Subscription + /** The transaction data provider. */ + transactionType: Subscription /** The tracked token prices which stored as address and price pairs. */ tokenPrices: Subscription /** The currently stored wallet by MaskWallet. */ @@ -263,6 +360,55 @@ export namespace Plugin.Shared { /** The default derivable wallet. */ walletPrimary: Subscription } + Asset?: { + /** Get fungible assets of given account. */ + getFungibleAssets( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ): Promise[]> + /** Get non-fungible assets of given account. */ + getNonFungibleAssets( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ): Promise[]> + } + Token?: { + addToken(token: Token): Promise + removeToken(token: Token): Promise + trustToken(token: Token): Promise + blockToken(token: Token): Promise + getFungibleTokenMetadata(token: Token): Promise> + getNonFungibleTokenMetadata(token: Token): Promise> + } + Transaction?: { + /** Get latest transactions of given account. */ + getTransactions( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ): Promise + } + TokenList?: { + /** Get the token lists of supported fungible tokens. */ + getFungibleTokenLists( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ): Promise[]> + /** Get the token lists of supported non-fungible tokens. */ + getNonFungibleTokenLists( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ): Promise[]> + } } } @@ -279,7 +425,7 @@ export namespace Plugin.SNSAdaptor { GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UIProvider?: Shared.Web3UIProvider - /** This is the web3 context. */ + /** This is the context of the currently choosen network. */ Web3ContextProvider?: Shared.Web3ContextProvider /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry @@ -373,7 +519,7 @@ export namespace Plugin.Dashboard { GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UIProvider?: Shared.Web3UIProvider - /** This is the web3 context. */ + /** This is the context of the currently choosen network. */ Web3ContextProvider?: Shared.Web3ContextProvider } } diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index 7a6065978d79..b121c7ddd129 100644 --- a/packages/web3-shared/evm/context/type.ts +++ b/packages/web3-shared/evm/context/type.ts @@ -61,5 +61,4 @@ export interface Web3ProviderType { hasNextPage: boolean }> fetchERC20TokensFromTokenLists: (urls: string[], chainId: ChainId) => Promise - createMnemonicWords: () => Promise } From 1b7b20b2460008b524fab6e9b00b3a10b450e542 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 15:30:17 +0800 Subject: [PATCH 13/41] refactor: createMnemonicWords --- .../src}/hooks/useMnemonicWordsPuzzle.ts | 9 ++++++--- .../CreateMaskWallet/components/CreateMnemonic/index.tsx | 3 ++- .../src/pages/SignUp/steps/MnemonicRevealForm.tsx | 2 +- packages/dashboard/src/web3/context.ts | 1 - packages/web3-shared/evm/hooks/index.ts | 1 - 5 files changed, 9 insertions(+), 7 deletions(-) rename packages/{web3-shared/evm => dashboard/src}/hooks/useMnemonicWordsPuzzle.ts (90%) diff --git a/packages/web3-shared/evm/hooks/useMnemonicWordsPuzzle.ts b/packages/dashboard/src/hooks/useMnemonicWordsPuzzle.ts similarity index 90% rename from packages/web3-shared/evm/hooks/useMnemonicWordsPuzzle.ts rename to packages/dashboard/src/hooks/useMnemonicWordsPuzzle.ts index 55ca02798a4f..0139e57e742a 100644 --- a/packages/web3-shared/evm/hooks/useMnemonicWordsPuzzle.ts +++ b/packages/dashboard/src/hooks/useMnemonicWordsPuzzle.ts @@ -1,7 +1,11 @@ +/** + * TODO: use @packages/plugin-wallet instead + */ + import { shuffle } from 'lodash-es' import { useCallback, useMemo, useState } from 'react' import { useAsyncRetry } from 'react-use' -import { useWeb3Context } from '../context' +import { WalletRPC } from '../../../mask/src/plugins/Wallet/messages' // How many fields should be filled by the user? const PUZZLE_SIZE = 5 @@ -11,12 +15,11 @@ const TOTAL_SIZE = 12 export function useMnemonicWordsPuzzle() { const [answerWords, setAnswerWords] = useState([]) - const { createMnemonicWords } = useWeb3Context() const { value: words = [], loading: wordsLoading, retry: wordsRetry, - } = useAsyncRetry(() => createMnemonicWords(), []) + } = useAsyncRetry(() => WalletRPC.createMnemonicWords(), []) //#region generate some mask indexes randomly which should be filled by the user const [seed, setSeed] = useState(0) diff --git a/packages/dashboard/src/pages/CreateMaskWallet/components/CreateMnemonic/index.tsx b/packages/dashboard/src/pages/CreateMaskWallet/components/CreateMnemonic/index.tsx index c7750bff3506..a36be6570a61 100644 --- a/packages/dashboard/src/pages/CreateMaskWallet/components/CreateMnemonic/index.tsx +++ b/packages/dashboard/src/pages/CreateMaskWallet/components/CreateMnemonic/index.tsx @@ -4,7 +4,7 @@ import { makeStyles } from '@masknet/theme' import { MaskColorVar } from '@masknet/theme' import { InfoIcon, RefreshIcon } from '@masknet/icons' import { useDashboardI18N } from '../../../../locales' -import { ProviderType, useMnemonicWordsPuzzle } from '@masknet/web3-shared-evm' +import { ProviderType } from '@masknet/web3-shared-evm' import { MnemonicReveal } from '../../../../components/Mnemonic' import { VerifyMnemonicDialog } from '../VerifyMnemonicDialog' import { useAsyncFn, useAsyncRetry } from 'react-use' @@ -13,6 +13,7 @@ import { PluginServices, Services } from '../../../../API' import { RoutePaths } from '../../../../type' import type { Search } from 'history' import { WalletMessages } from '@masknet/plugin-wallet' +import { useMnemonicWordsPuzzle } from '../../../../hooks/useMnemonicWordsPuzzle' // Private key at m/purpose'/coin_type'/account'/change export const HD_PATH_WITHOUT_INDEX_ETHEREUM = "m/44'/60'/0'/0" diff --git a/packages/dashboard/src/pages/SignUp/steps/MnemonicRevealForm.tsx b/packages/dashboard/src/pages/SignUp/steps/MnemonicRevealForm.tsx index a63952555d10..c8d239c90377 100644 --- a/packages/dashboard/src/pages/SignUp/steps/MnemonicRevealForm.tsx +++ b/packages/dashboard/src/pages/SignUp/steps/MnemonicRevealForm.tsx @@ -2,7 +2,6 @@ import { memo, useState } from 'react' import { some } from 'lodash-es' import { useNavigate } from 'react-router-dom' import { Button, Stack, Box } from '@mui/material' -import { useMnemonicWordsPuzzle } from '@masknet/web3-shared-evm' import RefreshIcon from '@mui/icons-material/Refresh' import { useCustomSnackbar } from '@masknet/theme' import { RoutePaths } from '../../../type' @@ -13,6 +12,7 @@ import { useDashboardI18N } from '../../../locales' import { DesktopMnemonicConfirm, MnemonicReveal } from '../../../components/Mnemonic' import { SignUpRoutePath } from '../routePath' import { ButtonContainer } from '../../../components/RegisterFrame/ButtonContainer' +import { useMnemonicWordsPuzzle } from '../../../hooks/useMnemonicWordsPuzzle' enum CreateWalletStep { NameAndWords = 0, diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index 960c50eb8350..eeb8fe8ef70e 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -95,7 +95,6 @@ export const Web3Context: Web3ProviderType = { getAddressNamesList: PluginServices.Wallet.getAddressNames, getTransactionList: PluginServices.Wallet.getTransactionList, fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, - createMnemonicWords: PluginServices.Wallet.createMnemonicWords, } export function createExternalProvider() { diff --git a/packages/web3-shared/evm/hooks/index.ts b/packages/web3-shared/evm/hooks/index.ts index 3a57ae5c7bef..20153a48b60c 100644 --- a/packages/web3-shared/evm/hooks/index.ts +++ b/packages/web3-shared/evm/hooks/index.ts @@ -53,7 +53,6 @@ export * from './useAssets' export * from './useAssetsByTokenList' export * from './useCollectibles' export * from './useTransactions' -export * from './useMnemonicWordsPuzzle' export * from './useGetPastLogsParams' export * from './useChainColor' export * from './useResolveENS' From 27ecbebdd60c7f8ff0b411245fd24454f05c2e52 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 20:01:53 +0800 Subject: [PATCH 14/41] refacotr: web3 hooks --- .../CompositionDialog/PluginEntryRender.tsx | 4 +- .../InjectedComponents/ToolboxUnstyled.tsx | 4 +- .../src/plugins/EVM/UI/Dashboard/index.tsx | 4 +- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 4 +- .../UI/{Web3UIProvider => Web3UI}/index.tsx | 2 +- .../SNSAdaptor/SelectProviderDialog/index.tsx | 8 +- packages/plugin-infra/package.json | 3 +- packages/plugin-infra/src/hooks/index.ts | 5 +- .../src/hooks/useRegisteredPluginNetwork.ts | 2 +- .../src/hooks/useRegisteredPluginProvider.ts | 2 +- .../plugin-infra/src/hooks/useWeb3Context.ts | 6 ++ .../src/hooks/useWeb3ContextProvider.ts | 6 -- packages/plugin-infra/src/hooks/useWeb3UI.ts | 6 ++ .../src/hooks/useWeb3UIProvider.ts | 6 -- packages/plugin-infra/src/index.ts | 3 +- .../plugin-infra/src/manager/sns-adaptor.ts | 4 +- packages/plugin-infra/src/types.ts | 41 ++++++--- .../src/web3/Web3ContextProvider.tsx | 83 +++++++++++++++++++ packages/plugin-infra/src/web3/index.ts | 19 +++++ packages/plugin-infra/src/web3/useAccount.ts | 10 +++ .../plugin-infra/src/web3/useAllowTestnet.ts | 5 ++ .../plugin-infra/src/web3/useAssetType.ts | 5 ++ packages/plugin-infra/src/web3/useBalance.ts | 8 ++ .../plugin-infra/src/web3/useBlockNumber.ts | 22 +++++ .../plugin-infra/src/web3/useChainDetailed.ts | 5 ++ packages/plugin-infra/src/web3/useChainId.ts | 27 ++++++ .../src/web3/useCollectibleType.ts | 5 ++ .../plugin-infra/src/web3/useCurrencyType.ts | 5 ++ packages/plugin-infra/src/web3/useNameType.ts | 5 ++ .../plugin-infra/src/web3/useNetworkType.ts | 5 ++ .../plugin-infra/src/web3/useProviderType.ts | 5 ++ .../plugin-infra/src/web3/useTokenPrice.ts | 7 ++ .../src/web3/useTransactionType.ts | 5 ++ packages/plugin-infra/src/web3/useWallet.ts | 8 ++ .../plugin-infra/src/web3/useWalletPrimary.ts | 6 ++ packages/plugin-infra/src/web3/useWallets.ts | 6 ++ packages/plugin-infra/tsconfig.json | 2 +- .../plugins/Flow/src/UI/Dashboard/index.tsx | 4 +- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 4 +- .../UI/{Web3UIProvider => Web3UI}/index.tsx | 2 +- packages/web3-shared/evm/hooks/useChainId.ts | 2 - pnpm-lock.yaml | 6 +- 42 files changed, 317 insertions(+), 54 deletions(-) rename packages/mask/src/plugins/EVM/UI/{Web3UIProvider => Web3UI}/index.tsx (83%) create mode 100644 packages/plugin-infra/src/hooks/useWeb3Context.ts delete mode 100644 packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts create mode 100644 packages/plugin-infra/src/hooks/useWeb3UI.ts delete mode 100644 packages/plugin-infra/src/hooks/useWeb3UIProvider.ts create mode 100644 packages/plugin-infra/src/web3/Web3ContextProvider.tsx create mode 100644 packages/plugin-infra/src/web3/index.ts create mode 100644 packages/plugin-infra/src/web3/useAccount.ts create mode 100644 packages/plugin-infra/src/web3/useAllowTestnet.ts create mode 100644 packages/plugin-infra/src/web3/useAssetType.ts create mode 100644 packages/plugin-infra/src/web3/useBalance.ts create mode 100644 packages/plugin-infra/src/web3/useBlockNumber.ts create mode 100644 packages/plugin-infra/src/web3/useChainDetailed.ts create mode 100644 packages/plugin-infra/src/web3/useChainId.ts create mode 100644 packages/plugin-infra/src/web3/useCollectibleType.ts create mode 100644 packages/plugin-infra/src/web3/useCurrencyType.ts create mode 100644 packages/plugin-infra/src/web3/useNameType.ts create mode 100644 packages/plugin-infra/src/web3/useNetworkType.ts create mode 100644 packages/plugin-infra/src/web3/useProviderType.ts create mode 100644 packages/plugin-infra/src/web3/useTokenPrice.ts create mode 100644 packages/plugin-infra/src/web3/useTransactionType.ts create mode 100644 packages/plugin-infra/src/web3/useWallet.ts create mode 100644 packages/plugin-infra/src/web3/useWalletPrimary.ts create mode 100644 packages/plugin-infra/src/web3/useWallets.ts rename packages/plugins/Flow/src/UI/{Web3UIProvider => Web3UI}/index.tsx (91%) diff --git a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx index f7d7467e3e9c..b6602a7a00f4 100644 --- a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx +++ b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx @@ -11,6 +11,7 @@ import { ITO_PluginID } from '../../plugins/ITO/constants' import { ClickableChip } from '../shared/SelectRecipients/ClickableChip' import { makeStyles } from '@masknet/theme' import { useCallback, useState, useRef, forwardRef, memo, useImperativeHandle } from 'react' +import { useChainId } from '@masknet/web3-shared-evm' const useStyles = makeStyles()({ sup: { @@ -24,7 +25,8 @@ export const PluginEntryRender = memo( forwardRef((props, ref) => { const [trackPluginRef] = useSetPluginEntryRenderRef(ref) const pluginField = usePluginI18NField() - const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet() + const chainId = useChainId() + const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId) const result = [...useActivatedPluginsSNSAdaptor()] .sort((plugin) => { // TODO: support priority order diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 012bff350a85..7aae1e30d68f 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -20,6 +20,7 @@ import { useWallet, formatEthereumAddress, TransactionStatusType, + useChainId, } from '@masknet/web3-shared-evm' import { useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet, @@ -171,11 +172,12 @@ function useToolbox() { const { classes } = useStyles() const { t } = useI18N() const account = useAccount() + const chainId = useChainId() const selectedWallet = useWallet() const chainColor = useChainColor() const chainIdValid = useChainIdValid() const chainDetailed = useChainDetailed() - const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet() + const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId) //#region recent pending transactions const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index 50e206f88c3d..edc71f6a55fe 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3UIProvider } from '../Web3UIProvider' +import { Web3UI } from '../Web3UI' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3UIProvider, + Web3UI, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index 50e206f88c3d..edc71f6a55fe 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3UIProvider } from '../Web3UIProvider' +import { Web3UI } from '../Web3UI' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3UIProvider, + Web3UI, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx similarity index 83% rename from packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx rename to packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx index a8ec08d4ac30..bafbdeec7939 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3UIProvider/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx @@ -2,7 +2,7 @@ import type { Plugin } from '@masknet/plugin-infra' import { useNetwork, useProvider } from '../../hooks' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UIProvider: Plugin.Shared.Web3UIProvider = { +export const Web3UI: Plugin.Shared.Web3UI = { Shared: { useNetwork, useProvider, diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 03ff7bf63bd6..1a519e9ed1f8 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -9,7 +9,7 @@ import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' -import { useRegisteredNetworks, useRegisteredProviders, useWeb3UIProvider } from '@masknet/plugin-infra' +import { useRegisteredNetworks, useRegisteredProviders, useWeb3UI } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ content: { @@ -46,9 +46,9 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const Web3UIProvider = useWeb3UIProvider(pluginID) - const { useNetwork = () => null } = Web3UIProvider?.Shared ?? {} - const { NetworkIconClickBait, ProviderIconClickBait } = Web3UIProvider?.SelectProviderDialog ?? {} + const Web3UI = useWeb3UI(pluginID) + const { useNetwork = () => null } = Web3UI?.Shared ?? {} + const { NetworkIconClickBait, ProviderIconClickBait } = Web3UI?.SelectProviderDialog ?? {} // not available for the native app if (hasNativeAPI) return null diff --git a/packages/plugin-infra/package.json b/packages/plugin-infra/package.json index b7df78ea824d..9125e047d843 100644 --- a/packages/plugin-infra/package.json +++ b/packages/plugin-infra/package.json @@ -9,11 +9,12 @@ "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@masknet/shared": "workspace:*", "@masknet/theme": "workspace:*", - "@masknet/web3-shared-evm": "workspace:*", "@servie/events": "^3.0.0", "@types/use-subscription": "^1.0.0", "async-call-rpc": "^6.0.0", + "lodash-es": "^4.17.21", "ts-results": "^3.3.0", + "unstated-next": "^1.1.0", "use-subscription": "^1.5.1" } } diff --git a/packages/plugin-infra/src/hooks/index.ts b/packages/plugin-infra/src/hooks/index.ts index a19017fdde9d..a22ff9913ab6 100644 --- a/packages/plugin-infra/src/hooks/index.ts +++ b/packages/plugin-infra/src/hooks/index.ts @@ -2,5 +2,6 @@ export * from './useActivatedPlugin' export * from './useRegisteredPlugin' export * from './useRegisteredPluginNetwork' export * from './useRegisteredPluginProvider' -export * from './useWeb3UIProvider' -export * from './useWeb3ContextProvider' + +export * from './useWeb3UI' +export * from './useWeb3Context' diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts index 51b945243192..d26806c0be29 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts @@ -1,4 +1,4 @@ -import { useRegisteredPlugin } from './' +import { useRegisteredPlugin } from '.' export function useRegisteredPluginNetwork(pluginID: string, networkID: string) { return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.ID === networkID) diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts index 8c4a636c6cda..7682c20f7e9f 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts @@ -1,4 +1,4 @@ -import { useRegisteredPlugin } from './' +import { useRegisteredPlugin } from '.' export function useRegisteredPluginProvider(pluginID: string, providerID: string) { return useRegisteredPlugin(pluginID)?.providers?.find((x) => x.ID === providerID) diff --git a/packages/plugin-infra/src/hooks/useWeb3Context.ts b/packages/plugin-infra/src/hooks/useWeb3Context.ts new file mode 100644 index 000000000000..632e1a41064c --- /dev/null +++ b/packages/plugin-infra/src/hooks/useWeb3Context.ts @@ -0,0 +1,6 @@ +import { useActivatedPlugin } from '.' + +export function useWeb3Context(pluginID: string) { + const activatedPlugin = useActivatedPlugin(pluginID) + return activatedPlugin?.Web3Context ?? null +} diff --git a/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts b/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts deleted file mode 100644 index fc0c121e9931..000000000000 --- a/packages/plugin-infra/src/hooks/useWeb3ContextProvider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useActivatedPlugin } from './useActivatedPlugin' - -export function useWeb3ContextProvider(pluginID: string) { - const activatedPlugin = useActivatedPlugin(pluginID) - return activatedPlugin?.Web3ContextProvider ?? null -} diff --git a/packages/plugin-infra/src/hooks/useWeb3UI.ts b/packages/plugin-infra/src/hooks/useWeb3UI.ts new file mode 100644 index 000000000000..d51e8f9992b6 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useWeb3UI.ts @@ -0,0 +1,6 @@ +import { useActivatedPlugin } from '.' + +export function useWeb3UI(pluginID: string) { + const activatedPlugin = useActivatedPlugin(pluginID) + return activatedPlugin?.Web3UI ?? null +} diff --git a/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts b/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts deleted file mode 100644 index 945f1e03f71d..000000000000 --- a/packages/plugin-infra/src/hooks/useWeb3UIProvider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useActivatedPlugin } from './useActivatedPlugin' - -export function useWeb3UIProvider(pluginID: string) { - const activatedPlugin = useActivatedPlugin(pluginID) - return activatedPlugin?.Web3UIProvider ?? null -} diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 59005fd6b0f8..18596d91c46e 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -1,9 +1,10 @@ +export * from './hooks' +export * from './web3' export * from './types' export * from './manager/dashboard' export * from './manager/sns-adaptor' export * from './manager/worker' export * from './utils' -export * from './hooks' export * from './PostContext' export * from 'ts-results' export { diff --git a/packages/plugin-infra/src/manager/sns-adaptor.ts b/packages/plugin-infra/src/manager/sns-adaptor.ts index 81ec6d75b091..89e87b748d2b 100644 --- a/packages/plugin-infra/src/manager/sns-adaptor.ts +++ b/packages/plugin-infra/src/manager/sns-adaptor.ts @@ -3,7 +3,6 @@ import { useSubscription, Subscription } from 'use-subscription' import { createManager } from './manage' import { getPluginDefine } from './store' import type { CurrentSNSNetwork, Plugin } from '../types' -import { useChainId } from '@masknet/web3-shared-evm' const { events, activated, startDaemon } = createManager((def) => def.SNSAdaptor) @@ -20,8 +19,7 @@ export function useActivatedPluginSNSAdaptor(pluginID: string) { return plugins.find((x) => x.ID === pluginID) } -export function useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet() { - const chainId = useChainId() +export function useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId: number) { const plugins = useActivatedPluginsSNSAdaptor() return plugins.reduce>((acc, cur) => { const operatingSupportedChains = cur.enableRequirement.web3?.operatingSupportedChains diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index f2fab5d907b9..9376235ad063 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -1,7 +1,6 @@ import type React from 'react' import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' -import type { ChainId, NonFungibleToken } from '@masknet/web3-shared-evm' import type { Emitter } from '@servie/events' import type { Subscription } from 'use-subscription' @@ -145,7 +144,7 @@ export namespace Plugin.Shared { } export interface Web3EnableRequirement { /** Plugin can declare what chain it supports. When the current chain is not supported, the composition entry will be hidden. */ - operatingSupportedChains?: ChainId[] + operatingSupportedChains?: number[] } export interface ManagementProperty { @@ -199,7 +198,7 @@ export namespace Plugin.Shared { name: string } - export interface Web3UIProvider { + export interface Web3UI { Shared?: { /** A react hook returns the currently selected provider. */ useProvider?: () => Shared.Provider | null @@ -217,7 +216,6 @@ export namespace Plugin.Shared { }> } Dashboard?: { - /** There UIs will be injected into the wallet table of Dashboard. */ OverviewComponent?: React.ComponentType<{}> AssetsTableComponent?: React.ComponentType<{}> TransferTableComponent?: React.ComponentType<{}> @@ -242,6 +240,15 @@ export namespace Plugin.Shared { } } + export interface ChainDetailed { + name: string + chainId: number + fullName: string + shortName: string + chainName: string + networkName: string + } + export interface Wallet { /** User define wallet name. Default address.prefix(6) */ name: string @@ -330,7 +337,7 @@ export namespace Plugin.Shared { tokens: Token[] } - export interface Web3ContextProvider { + export interface Web3Context { Shared?: { allowTestnet: Subscription /** The ID of currently choosen sub-network. */ @@ -353,12 +360,18 @@ export namespace Plugin.Shared { collectibleType: Subscription /** The transaction data provider. */ transactionType: Subscription + /** The currency of estimated values and prices. */ + currencyType: Subscription /** The tracked token prices which stored as address and price pairs. */ - tokenPrices: Subscription + prices: Subscription /** The currently stored wallet by MaskWallet. */ wallets: Subscription /** The default derivable wallet. */ walletPrimary: Subscription + /** The user added fungible tokens. */ + fungibleTokens: Subscription[]> + /** The user added non-fungible tokens. */ + nonFungibleTokens: Subscription[]> } Asset?: { /** Get fungible assets of given account. */ @@ -381,8 +394,6 @@ export namespace Plugin.Shared { removeToken(token: Token): Promise trustToken(token: Token): Promise blockToken(token: Token): Promise - getFungibleTokenMetadata(token: Token): Promise> - getNonFungibleTokenMetadata(token: Token): Promise> } Transaction?: { /** Get latest transactions of given account. */ @@ -409,6 +420,12 @@ export namespace Plugin.Shared { pagination?: Pagination, ): Promise[]> } + Utils?: { + isChainIdValid(chainId: number, allowTestnet: boolean): boolean + getChainDetailed(chainId: number): ChainDetailed + getFungibleTokenMetadata(token: Token): Promise> + getNonFungibleTokenMetadata(token: Token): Promise> + } } } @@ -424,9 +441,9 @@ export namespace Plugin.SNSAdaptor { /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UIProvider?: Shared.Web3UIProvider + Web3UI?: Shared.Web3UI /** This is the context of the currently choosen network. */ - Web3ContextProvider?: Shared.Web3ContextProvider + Web3Context?: Shared.Web3Context /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -518,9 +535,9 @@ export namespace Plugin.Dashboard { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UIProvider?: Shared.Web3UIProvider + Web3UI?: Shared.Web3UI /** This is the context of the currently choosen network. */ - Web3ContextProvider?: Shared.Web3ContextProvider + Web3Context?: Shared.Web3Context } } diff --git a/packages/plugin-infra/src/web3/Web3ContextProvider.tsx b/packages/plugin-infra/src/web3/Web3ContextProvider.tsx new file mode 100644 index 000000000000..753220f55366 --- /dev/null +++ b/packages/plugin-infra/src/web3/Web3ContextProvider.tsx @@ -0,0 +1,83 @@ +import { noop } from 'lodash-es' +import React, { createContext, useContext } from 'react' +import { createContainer } from 'unstated-next' +import { useSubscription } from 'use-subscription' +import type { Plugin } from '..' + +function createSubscription(value: T) { + return { + getCurrentValue: () => value, + subscribe: () => noop, + } +} + +const ZERO = createSubscription(0) +const ZERO_STRING = createSubscription('0') +const EMPTY_STRING = createSubscription('') +const EMPTY_ARRAY = createSubscription([]) +const FALSE = createSubscription(false) +const NULL = createSubscription(null) + +function useWeb3Context() { + const context = useContext(Web3Context) + if (!context) throw new Error('This hook should be used in a provider.') + return context +} + +export function useWeb3State() { + const { Shared, Utils } = useWeb3Context() + const allowTestnet = useSubscription(Shared?.allowTestnet ?? FALSE) + const chainId = useSubscription(Shared?.chainId ?? ZERO) + const account = useSubscription(Shared?.account ?? EMPTY_STRING) + const balance = useSubscription(Shared?.balance ?? ZERO_STRING) + const blockNumber = useSubscription(Shared?.blockNumber ?? ZERO) + const networkType = useSubscription(Shared?.networkType ?? EMPTY_STRING) + const providerType = useSubscription(Shared?.providerType ?? EMPTY_STRING) + const assetType = useSubscription(Shared?.assetType ?? EMPTY_STRING) + const nameType = useSubscription(Shared?.nameType ?? EMPTY_STRING) + const collectibleType = useSubscription(Shared?.collectibleType ?? EMPTY_STRING) + const transactionType = useSubscription(Shared?.transactionType ?? EMPTY_STRING) + const currencyType = useSubscription( + Shared?.currencyType ?? createSubscription('usd' as Plugin.Shared.CurrencyType), + ) + const prices = useSubscription(Shared?.prices ?? NULL) + const walletPrimary = useSubscription(Shared?.walletPrimary ?? NULL) + const wallets = useSubscription(Shared?.wallets ?? EMPTY_ARRAY) + const fungibleTokens = useSubscription(Shared?.fungibleTokens ?? EMPTY_ARRAY) + const nonFungibleTokens = useSubscription(Shared?.nonFungibleTokens ?? EMPTY_ARRAY) + + return { + allowTestnet, + chainId, + chainIdValid: !account || (Utils?.isChainIdValid(chainId, allowTestnet) ?? false), + chainDetailed: Utils?.getChainDetailed(chainId) ?? null, + account, + balance, + blockNumber, + networkType, + providerType, + assetType, + nameType, + collectibleType, + transactionType, + currencyType, + prices, + walletPrimary, + wallets, + fungibleTokens, + nonFungibleTokens, + } +} + +export const Web3Context = createContext(null!) +export const Web3StateContext = createContainer(useWeb3State) + +export const useWeb3StateContext = Web3StateContext.useContainer + +export function Web3ContextProvider({ value, children }: React.ProviderProps) { + return ( + + {children} + + ) +} diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts new file mode 100644 index 000000000000..57daabca5b78 --- /dev/null +++ b/packages/plugin-infra/src/web3/index.ts @@ -0,0 +1,19 @@ +export * from './useAccount' +export * from './useAllowTestnet' +export * from './useAssetType' +export * from './useBalance' +export * from './useBlockNumber' +export * from './useChainDetailed' +export * from './useChainId' +export * from './useCollectibleType' +export * from './useNameType' +export * from './useNetworkType' +export * from './useProviderType' +export * from './useTokenPrice' +export * from './useTransactionType' +export * from './useWallet' +export * from './useWalletPrimary' +export * from './useWallets' + +// context & provider +export * from './Web3ContextProvider' diff --git a/packages/plugin-infra/src/web3/useAccount.ts b/packages/plugin-infra/src/web3/useAccount.ts new file mode 100644 index 000000000000..7977be661f4b --- /dev/null +++ b/packages/plugin-infra/src/web3/useAccount.ts @@ -0,0 +1,10 @@ +import { first } from 'lodash-es' +import { useWeb3StateContext } from '.' + +/** + * Get the address of the default wallet + */ +export function useAccount() { + const { account, wallets } = useWeb3StateContext() + return process.env.architecture === 'app' ? first(wallets)?.address ?? '' : account +} diff --git a/packages/plugin-infra/src/web3/useAllowTestnet.ts b/packages/plugin-infra/src/web3/useAllowTestnet.ts new file mode 100644 index 000000000000..38925700c179 --- /dev/null +++ b/packages/plugin-infra/src/web3/useAllowTestnet.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useAllowTestnet() { + return useWeb3StateContext().allowTestnet +} diff --git a/packages/plugin-infra/src/web3/useAssetType.ts b/packages/plugin-infra/src/web3/useAssetType.ts new file mode 100644 index 000000000000..cd7677644efe --- /dev/null +++ b/packages/plugin-infra/src/web3/useAssetType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useAssetType() { + return useWeb3StateContext().assetType +} diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts new file mode 100644 index 000000000000..ddb737ecde90 --- /dev/null +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -0,0 +1,8 @@ +import { useWeb3StateContext } from '.' + +/** + * Get the current block number + */ +export function useBalance() { + return useWeb3StateContext().balance +} diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts new file mode 100644 index 000000000000..715a9b33460e --- /dev/null +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -0,0 +1,22 @@ +import { useState, useEffect } from 'react' +import { useWeb3StateContext } from '.' + +/** + * Get the current block number of current chain + */ +export function useBlockNumber() { + return useWeb3StateContext().blockNumber +} + +/** + * Get the current block number only once + * @returns + */ +export function useBlockNumberOnce() { + const blockNumber = useBlockNumber() + const [blockNumberOnce, setBlockNumberOnce] = useState(0) + useEffect(() => { + if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) + }, [blockNumber]) + return blockNumberOnce +} diff --git a/packages/plugin-infra/src/web3/useChainDetailed.ts b/packages/plugin-infra/src/web3/useChainDetailed.ts new file mode 100644 index 000000000000..baf496f5ca79 --- /dev/null +++ b/packages/plugin-infra/src/web3/useChainDetailed.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useChainDetailed() { + return useWeb3StateContext().chainDetailed +} diff --git a/packages/plugin-infra/src/web3/useChainId.ts b/packages/plugin-infra/src/web3/useChainId.ts new file mode 100644 index 000000000000..ca689da2bc87 --- /dev/null +++ b/packages/plugin-infra/src/web3/useChainId.ts @@ -0,0 +1,27 @@ +import { useWeb3StateContext, useChainDetailed } from '.' + +/** + * Get the chain id which is using by the given (or default) wallet + * It will always yield Mainnet in production mode + */ +export function useChainId() { + return useWeb3StateContext().chainId +} + +/** + * Returns true if chain id is available + */ +export function useChainIdValid() { + return useWeb3StateContext().chainIdValid +} + +/** + * Returns true if the current chain id is matched with the given one + * @param chainId + * @returns + */ +export function useChainIdMatched(chainId?: number) { + const chainDetailed = useChainDetailed() + if (!chainId) return false + return chainDetailed?.chainId === chainId +} diff --git a/packages/plugin-infra/src/web3/useCollectibleType.ts b/packages/plugin-infra/src/web3/useCollectibleType.ts new file mode 100644 index 000000000000..aec036ae9c20 --- /dev/null +++ b/packages/plugin-infra/src/web3/useCollectibleType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useCollectibleType() { + return useWeb3StateContext().collectibleType +} diff --git a/packages/plugin-infra/src/web3/useCurrencyType.ts b/packages/plugin-infra/src/web3/useCurrencyType.ts new file mode 100644 index 000000000000..dc017bc2b611 --- /dev/null +++ b/packages/plugin-infra/src/web3/useCurrencyType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useCurrencyType() { + return useWeb3StateContext().currencyType +} diff --git a/packages/plugin-infra/src/web3/useNameType.ts b/packages/plugin-infra/src/web3/useNameType.ts new file mode 100644 index 000000000000..0acd09b75f33 --- /dev/null +++ b/packages/plugin-infra/src/web3/useNameType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useNameType() { + return useWeb3StateContext().nameType +} diff --git a/packages/plugin-infra/src/web3/useNetworkType.ts b/packages/plugin-infra/src/web3/useNetworkType.ts new file mode 100644 index 000000000000..4f69126b46c1 --- /dev/null +++ b/packages/plugin-infra/src/web3/useNetworkType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useNetworkType() { + return useWeb3StateContext().networkType +} diff --git a/packages/plugin-infra/src/web3/useProviderType.ts b/packages/plugin-infra/src/web3/useProviderType.ts new file mode 100644 index 000000000000..49ece26362eb --- /dev/null +++ b/packages/plugin-infra/src/web3/useProviderType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useProviderType() { + return useWeb3StateContext().providerType +} diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts new file mode 100644 index 000000000000..d87b9fa4c0d5 --- /dev/null +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -0,0 +1,7 @@ +import { useWeb3StateContext } from '.' +import type { Plugin } from '..' + +export function useTokenPrice(id: string, currencyType: string) { + const { prices } = useWeb3StateContext() ?? {} + return prices?.[id][currencyType as Plugin.Shared.CurrencyType] ?? 0 +} diff --git a/packages/plugin-infra/src/web3/useTransactionType.ts b/packages/plugin-infra/src/web3/useTransactionType.ts new file mode 100644 index 000000000000..cb18ef9a2ee2 --- /dev/null +++ b/packages/plugin-infra/src/web3/useTransactionType.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '.' + +export function useTransactionType() { + return useWeb3StateContext().transactionType +} diff --git a/packages/plugin-infra/src/web3/useWallet.ts b/packages/plugin-infra/src/web3/useWallet.ts new file mode 100644 index 000000000000..5ce175591df5 --- /dev/null +++ b/packages/plugin-infra/src/web3/useWallet.ts @@ -0,0 +1,8 @@ +import { useAccount } from '.' +import { useWeb3StateContext } from '.' + +export function useWallet() { + const account = useAccount() + const { wallets } = useWeb3StateContext() + return account ? wallets.find((x) => x.address.toLowerCase() === account.toLowerCase()) : undefined +} diff --git a/packages/plugin-infra/src/web3/useWalletPrimary.ts b/packages/plugin-infra/src/web3/useWalletPrimary.ts new file mode 100644 index 000000000000..270a455b7b4d --- /dev/null +++ b/packages/plugin-infra/src/web3/useWalletPrimary.ts @@ -0,0 +1,6 @@ +import { useWeb3StateContext } from '.' + +export function useWalletPrimary() { + const { walletPrimary } = useWeb3StateContext() + return walletPrimary +} diff --git a/packages/plugin-infra/src/web3/useWallets.ts b/packages/plugin-infra/src/web3/useWallets.ts new file mode 100644 index 000000000000..5b379d8b2765 --- /dev/null +++ b/packages/plugin-infra/src/web3/useWallets.ts @@ -0,0 +1,6 @@ +import { useWeb3StateContext } from '.' + +export function useWallets(type?: string) { + const { wallets } = useWeb3StateContext() + return wallets +} diff --git a/packages/plugin-infra/tsconfig.json b/packages/plugin-infra/tsconfig.json index ddf6ae0a216c..cb9eb0fc85bc 100644 --- a/packages/plugin-infra/tsconfig.json +++ b/packages/plugin-infra/tsconfig.json @@ -6,7 +6,7 @@ "tsBuildInfoFile": "./dist/.tsbuildinfo" }, "include": ["./src"], - "references": [{ "path": "../shared/" }, { "path": "../theme" }, { "path": "../web3-shared/evm/" }], + "references": [{ "path": "../shared/" }, { "path": "../theme" }], "ts-node": { "transpileOnly": true, "compilerOptions": { "module": "CommonJS" } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index 590c21f9a4ec..9c9587f1417c 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' -import { Web3UIProvider } from '../Web3UIProvider' +import { Web3UI } from '../Web3UI' const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, - Web3UIProvider, + Web3UI, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index 50e206f88c3d..edc71f6a55fe 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' -import { Web3UIProvider } from '../Web3UIProvider' +import { Web3UI } from '../Web3UI' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, - Web3UIProvider, + Web3UI, } export default sns diff --git a/packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx b/packages/plugins/Flow/src/UI/Web3UI/index.tsx similarity index 91% rename from packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx rename to packages/plugins/Flow/src/UI/Web3UI/index.tsx index f26434d9ba2d..f391a6ae6504 100644 --- a/packages/plugins/Flow/src/UI/Web3UIProvider/index.tsx +++ b/packages/plugins/Flow/src/UI/Web3UI/index.tsx @@ -3,7 +3,7 @@ import { useNetworkType, useProviderType } from '@masknet/web3-shared-flow' import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UIProvider: Plugin.Shared.Web3UIProvider = { +export const Web3UI: Plugin.Shared.Web3UI = { Shared: { useNetwork() { const networkType = useNetworkType() diff --git a/packages/web3-shared/evm/hooks/useChainId.ts b/packages/web3-shared/evm/hooks/useChainId.ts index e1d50283d558..e30ede50f6ae 100644 --- a/packages/web3-shared/evm/hooks/useChainId.ts +++ b/packages/web3-shared/evm/hooks/useChainId.ts @@ -27,5 +27,3 @@ export function useChainIdMatched(chainId?: ChainId) { if (!chainId) return false return chainDetailed?.chainId === chainId } - -export const useChainIDAvailable = useChainId diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 401268eaffcb..f07c9c86ce35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -542,21 +542,23 @@ importers: '@dimensiondev/holoflows-kit': ^0.9.0-20210902104757-7c3d0d0 '@masknet/shared': workspace:* '@masknet/theme': workspace:* - '@masknet/web3-shared-evm': workspace:* '@servie/events': ^3.0.0 '@types/use-subscription': ^1.0.0 async-call-rpc: ^6.0.0 + lodash-es: ^4.17.21 ts-results: ^3.3.0 + unstated-next: ^1.1.0 use-subscription: ^1.5.1 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 '@masknet/shared': link:../shared '@masknet/theme': link:../theme - '@masknet/web3-shared-evm': link:../web3-shared/evm '@servie/events': 3.0.0 '@types/use-subscription': 1.0.0 async-call-rpc: 6.0.0 + lodash-es: 4.17.21 ts-results: 3.3.0 + unstated-next: 1.1.0 use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c packages/plugins/Flow: From 8cf1f8d660e8bf0fd691da3b794ba17b318a69c0 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 21:26:10 +0800 Subject: [PATCH 15/41] refactor: add context --- .../src/initialization/Dashboard.tsx | 58 +++++++++++-------- packages/dashboard/src/pages/Personas/api.ts | 10 ++++ .../background-script/SettingsService.ts | 4 ++ .../SNSAdaptor/SelectProviderDialog/index.tsx | 5 +- packages/mask/src/settings/listener.ts | 4 ++ .../index.tsx} | 22 +++---- packages/plugin-infra/src/hooks/index.ts | 5 +- ...xt.ts => useActivatedPluginWeb3Context.ts} | 2 +- ...eWeb3UI.ts => useActivatedPluginWeb3UI.ts} | 2 +- packages/plugin-infra/src/index.ts | 3 +- packages/plugin-infra/src/web3/index.ts | 3 - packages/plugin-infra/src/web3/useAccount.ts | 4 +- .../plugin-infra/src/web3/useAllowTestnet.ts | 4 +- .../plugin-infra/src/web3/useAssetType.ts | 4 +- packages/plugin-infra/src/web3/useBalance.ts | 4 +- .../plugin-infra/src/web3/useBlockNumber.ts | 4 +- .../plugin-infra/src/web3/useChainDetailed.ts | 4 +- packages/plugin-infra/src/web3/useChainId.ts | 7 ++- .../src/web3/useCollectibleType.ts | 4 +- .../plugin-infra/src/web3/useCurrencyType.ts | 4 +- packages/plugin-infra/src/web3/useNameType.ts | 4 +- .../plugin-infra/src/web3/useNetworkType.ts | 4 +- .../plugin-infra/src/web3/useProviderType.ts | 4 +- .../plugin-infra/src/web3/useTokenPrice.ts | 4 +- .../src/web3/useTransactionType.ts | 4 +- packages/plugin-infra/src/web3/useWallet.ts | 4 +- .../plugin-infra/src/web3/useWalletPrimary.ts | 4 +- packages/plugin-infra/src/web3/useWallets.ts | 4 +- 28 files changed, 109 insertions(+), 80 deletions(-) rename packages/plugin-infra/src/{web3/Web3ContextProvider.tsx => context/index.tsx} (78%) rename packages/plugin-infra/src/hooks/{useWeb3Context.ts => useActivatedPluginWeb3Context.ts} (69%) rename packages/plugin-infra/src/hooks/{useWeb3UI.ts => useActivatedPluginWeb3UI.ts} (69%) diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index 6e26a948cda3..8bf972605672 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -9,7 +9,12 @@ import { NoEffectUsePortalShadowRootContext, } from '@masknet/theme' import { ErrorBoundary } from '@masknet/shared' -import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' +import { + createInjectHooksRenderer, + PluginWeb3ContextProvider, + useActivatedPluginsDashboard, + useActivatedPluginWeb3Context, +} from '@masknet/plugin-infra' import { Web3Provider } from '@masknet/web3-shared-evm' import i18n from 'i18next' @@ -18,43 +23,50 @@ import { I18nextProvider } from 'react-i18next' import './PluginHost' import { Pages } from '../pages/routes' import { Web3Context } from '../web3/context' -import { useAppearance } from '../pages/Personas/api' +import { useAppearance, usePluginID } from '../pages/Personas/api' import { PersonaContext } from '../pages/Personas/hooks/usePersonaContext' const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) => x.GlobalInjection) export default function DashboardRoot() { - const settings = useAppearance() + const pluginID = usePluginID() + const PluginWeb3Context = useActivatedPluginWeb3Context(pluginID) + + //#region theme + const appearance = useAppearance() const mode = useSystemPreferencePalette() - const themes: Record = { + const themes: Record = { dark: MaskDarkTheme, light: MaskLightTheme, default: mode === 'dark' ? MaskDarkTheme : MaskLightTheme, } - const theme = themes[settings] + const theme = themes[appearance] - applyMaskColorVars(document.body, settings === 'default' ? mode : settings) + applyMaskColorVars(document.body, appearance === 'default' ? mode : appearance) + //#endregion return ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + ) diff --git a/packages/dashboard/src/pages/Personas/api.ts b/packages/dashboard/src/pages/Personas/api.ts index 901dd704aed8..c4729a5640ef 100644 --- a/packages/dashboard/src/pages/Personas/api.ts +++ b/packages/dashboard/src/pages/Personas/api.ts @@ -4,10 +4,12 @@ import { Services, Messages } from '../../API' export type SocialNetwork = { networkIdentifier: string } + export const [useDefinedSocialNetworkUIs, revalidateSocialNetworkUIs] = createGlobalState( Services.SocialNetwork.getDefinedSocialNetworkUIs, () => () => {}, ) + export const [useOwnedPersonas] = createGlobalState(Services.Identity.queryOwnedPersonaInformation, (x) => Messages.events.ownPersonaChanged.on(x), ) @@ -16,6 +18,14 @@ export const [useAppearance] = createGlobalState(Services.Settings.getTheme, (x) Messages.events.appearanceSettings.on(x), ) +export const [usePluginID] = createGlobalState(Services.Settings.getPluginID, (x) => + Messages.events.pluginIDSettings.on(x), +) + +export const [useNetworkID] = createGlobalState(Services.Settings.getNetworkID, (x) => + Messages.events.networkIDSettings.on(x), +) + export const [useCurrentPersonaIdentifier] = createGlobalState(Services.Settings.getCurrentPersonaIdentifier, (x) => Messages.events.currentPersonaIdentifier.on(x), ) diff --git a/packages/mask/src/extension/background-script/SettingsService.ts b/packages/mask/src/extension/background-script/SettingsService.ts index 8fa6888fba50..a81b003a690c 100644 --- a/packages/mask/src/extension/background-script/SettingsService.ts +++ b/packages/mask/src/extension/background-script/SettingsService.ts @@ -6,6 +6,8 @@ import { currentPersonaIdentifier, languageSettings, currentPluginEnabledStatus, + pluginIDSettings, + networkIDSettings, } from '../../settings/settings' import { currentDataProviderSettings, @@ -46,6 +48,8 @@ function create(settings: InternalSettings) { } return [get, set] as const } +export const [getPluginID, setPluginID] = create(pluginIDSettings) +export const [getNetworkID, setNetworkID] = create(networkIDSettings) export const [getTheme, setTheme] = create(appearanceSettings) export const [getLanguage, setLanguage] = create(languageSettings) export const [getChainId, setChainId] = create(currentChainIdSettings) diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 1a519e9ed1f8..6a9165e3337e 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -9,7 +9,7 @@ import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' -import { useRegisteredNetworks, useRegisteredProviders, useWeb3UI } from '@masknet/plugin-infra' +import { useRegisteredNetworks, useRegisteredProviders, useActivatedPluginWeb3UI } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ content: { @@ -46,7 +46,8 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const Web3UI = useWeb3UI(pluginID) + const Web3UI = useActivatedPluginWeb3UI(pluginID) + const { useNetwork = () => null } = Web3UI?.Shared ?? {} const { NetworkIconClickBait, ProviderIconClickBait } = Web3UI?.SelectProviderDialog ?? {} diff --git a/packages/mask/src/settings/listener.ts b/packages/mask/src/settings/listener.ts index c67c6f2f9c54..2f564767ce58 100644 --- a/packages/mask/src/settings/listener.ts +++ b/packages/mask/src/settings/listener.ts @@ -2,6 +2,8 @@ import type { ValueRef } from '@dimensiondev/holoflows-kit' import { allPostReplacementSettings, appearanceSettings, + pluginIDSettings, + networkIDSettings, languageSettings, debugModeSetting, currentPersonaIdentifier, @@ -35,6 +37,8 @@ export function ToBeListened() { return { allPostReplacementSettings, appearanceSettings, + pluginIDSettings, + networkIDSettings, languageSettings, debugModeSetting, currentChainIdSettings, diff --git a/packages/plugin-infra/src/web3/Web3ContextProvider.tsx b/packages/plugin-infra/src/context/index.tsx similarity index 78% rename from packages/plugin-infra/src/web3/Web3ContextProvider.tsx rename to packages/plugin-infra/src/context/index.tsx index 753220f55366..119e2b02ca03 100644 --- a/packages/plugin-infra/src/web3/Web3ContextProvider.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -18,14 +18,14 @@ const EMPTY_ARRAY = createSubscription([]) const FALSE = createSubscription(false) const NULL = createSubscription(null) -function useWeb3Context() { - const context = useContext(Web3Context) +function usePluginWeb3Context() { + const context = useContext(PluginWeb3Context) if (!context) throw new Error('This hook should be used in a provider.') return context } -export function useWeb3State() { - const { Shared, Utils } = useWeb3Context() +export function usePluginWeb3State() { + const { Shared, Utils } = usePluginWeb3Context() const allowTestnet = useSubscription(Shared?.allowTestnet ?? FALSE) const chainId = useSubscription(Shared?.chainId ?? ZERO) const account = useSubscription(Shared?.account ?? EMPTY_STRING) @@ -69,15 +69,15 @@ export function useWeb3State() { } } -export const Web3Context = createContext(null!) -export const Web3StateContext = createContainer(useWeb3State) +export const PluginWeb3Context = createContext(null!) +export const PluginWeb3StateContext = createContainer(usePluginWeb3State) -export const useWeb3StateContext = Web3StateContext.useContainer +export const usePluginWeb3StateContext = PluginWeb3StateContext.useContainer -export function Web3ContextProvider({ value, children }: React.ProviderProps) { +export function PluginWeb3ContextProvider({ value, children }: React.ProviderProps) { return ( - - {children} - + + {children} + ) } diff --git a/packages/plugin-infra/src/hooks/index.ts b/packages/plugin-infra/src/hooks/index.ts index a22ff9913ab6..1a907e896d5a 100644 --- a/packages/plugin-infra/src/hooks/index.ts +++ b/packages/plugin-infra/src/hooks/index.ts @@ -1,7 +1,6 @@ export * from './useActivatedPlugin' +export * from './useActivatedPluginWeb3UI' +export * from './useActivatedPluginWeb3Context' export * from './useRegisteredPlugin' export * from './useRegisteredPluginNetwork' export * from './useRegisteredPluginProvider' - -export * from './useWeb3UI' -export * from './useWeb3Context' diff --git a/packages/plugin-infra/src/hooks/useWeb3Context.ts b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts similarity index 69% rename from packages/plugin-infra/src/hooks/useWeb3Context.ts rename to packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts index 632e1a41064c..3f0b52ee38c8 100644 --- a/packages/plugin-infra/src/hooks/useWeb3Context.ts +++ b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts @@ -1,6 +1,6 @@ import { useActivatedPlugin } from '.' -export function useWeb3Context(pluginID: string) { +export function useActivatedPluginWeb3Context(pluginID: string) { const activatedPlugin = useActivatedPlugin(pluginID) return activatedPlugin?.Web3Context ?? null } diff --git a/packages/plugin-infra/src/hooks/useWeb3UI.ts b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3UI.ts similarity index 69% rename from packages/plugin-infra/src/hooks/useWeb3UI.ts rename to packages/plugin-infra/src/hooks/useActivatedPluginWeb3UI.ts index d51e8f9992b6..0f41c2f7cad1 100644 --- a/packages/plugin-infra/src/hooks/useWeb3UI.ts +++ b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3UI.ts @@ -1,6 +1,6 @@ import { useActivatedPlugin } from '.' -export function useWeb3UI(pluginID: string) { +export function useActivatedPluginWeb3UI(pluginID: string) { const activatedPlugin = useActivatedPlugin(pluginID) return activatedPlugin?.Web3UI ?? null } diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 18596d91c46e..4388e9792149 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -1,6 +1,7 @@ -export * from './hooks' export * from './web3' +export * from './context' export * from './types' +export * from './hooks' export * from './manager/dashboard' export * from './manager/sns-adaptor' export * from './manager/worker' diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts index 57daabca5b78..670abf6fb00d 100644 --- a/packages/plugin-infra/src/web3/index.ts +++ b/packages/plugin-infra/src/web3/index.ts @@ -14,6 +14,3 @@ export * from './useTransactionType' export * from './useWallet' export * from './useWalletPrimary' export * from './useWallets' - -// context & provider -export * from './Web3ContextProvider' diff --git a/packages/plugin-infra/src/web3/useAccount.ts b/packages/plugin-infra/src/web3/useAccount.ts index 7977be661f4b..75cd39e97a5a 100644 --- a/packages/plugin-infra/src/web3/useAccount.ts +++ b/packages/plugin-infra/src/web3/useAccount.ts @@ -1,10 +1,10 @@ import { first } from 'lodash-es' -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' /** * Get the address of the default wallet */ export function useAccount() { - const { account, wallets } = useWeb3StateContext() + const { account, wallets } = usePluginWeb3StateContext() return process.env.architecture === 'app' ? first(wallets)?.address ?? '' : account } diff --git a/packages/plugin-infra/src/web3/useAllowTestnet.ts b/packages/plugin-infra/src/web3/useAllowTestnet.ts index 38925700c179..09bf809bf918 100644 --- a/packages/plugin-infra/src/web3/useAllowTestnet.ts +++ b/packages/plugin-infra/src/web3/useAllowTestnet.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useAllowTestnet() { - return useWeb3StateContext().allowTestnet + return usePluginWeb3StateContext().allowTestnet } diff --git a/packages/plugin-infra/src/web3/useAssetType.ts b/packages/plugin-infra/src/web3/useAssetType.ts index cd7677644efe..c386d1725d66 100644 --- a/packages/plugin-infra/src/web3/useAssetType.ts +++ b/packages/plugin-infra/src/web3/useAssetType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useAssetType() { - return useWeb3StateContext().assetType + return usePluginWeb3StateContext().assetType } diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts index ddb737ecde90..3d5339db8494 100644 --- a/packages/plugin-infra/src/web3/useBalance.ts +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -1,8 +1,8 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' /** * Get the current block number */ export function useBalance() { - return useWeb3StateContext().balance + return usePluginWeb3StateContext().balance } diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index 715a9b33460e..ee723acf455f 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -1,11 +1,11 @@ import { useState, useEffect } from 'react' -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' /** * Get the current block number of current chain */ export function useBlockNumber() { - return useWeb3StateContext().blockNumber + return usePluginWeb3StateContext().blockNumber } /** diff --git a/packages/plugin-infra/src/web3/useChainDetailed.ts b/packages/plugin-infra/src/web3/useChainDetailed.ts index baf496f5ca79..eb8d0338033c 100644 --- a/packages/plugin-infra/src/web3/useChainDetailed.ts +++ b/packages/plugin-infra/src/web3/useChainDetailed.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useChainDetailed() { - return useWeb3StateContext().chainDetailed + return usePluginWeb3StateContext().chainDetailed } diff --git a/packages/plugin-infra/src/web3/useChainId.ts b/packages/plugin-infra/src/web3/useChainId.ts index ca689da2bc87..56c47dff0b3a 100644 --- a/packages/plugin-infra/src/web3/useChainId.ts +++ b/packages/plugin-infra/src/web3/useChainId.ts @@ -1,18 +1,19 @@ -import { useWeb3StateContext, useChainDetailed } from '.' +import { useChainDetailed } from '.' +import { usePluginWeb3StateContext } from '../context' /** * Get the chain id which is using by the given (or default) wallet * It will always yield Mainnet in production mode */ export function useChainId() { - return useWeb3StateContext().chainId + return usePluginWeb3StateContext().chainId } /** * Returns true if chain id is available */ export function useChainIdValid() { - return useWeb3StateContext().chainIdValid + return usePluginWeb3StateContext().chainIdValid } /** diff --git a/packages/plugin-infra/src/web3/useCollectibleType.ts b/packages/plugin-infra/src/web3/useCollectibleType.ts index aec036ae9c20..4ef3b6bc556d 100644 --- a/packages/plugin-infra/src/web3/useCollectibleType.ts +++ b/packages/plugin-infra/src/web3/useCollectibleType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useCollectibleType() { - return useWeb3StateContext().collectibleType + return usePluginWeb3StateContext().collectibleType } diff --git a/packages/plugin-infra/src/web3/useCurrencyType.ts b/packages/plugin-infra/src/web3/useCurrencyType.ts index dc017bc2b611..18d1f466ac0e 100644 --- a/packages/plugin-infra/src/web3/useCurrencyType.ts +++ b/packages/plugin-infra/src/web3/useCurrencyType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useCurrencyType() { - return useWeb3StateContext().currencyType + return usePluginWeb3StateContext().currencyType } diff --git a/packages/plugin-infra/src/web3/useNameType.ts b/packages/plugin-infra/src/web3/useNameType.ts index 0acd09b75f33..0a4c906babf7 100644 --- a/packages/plugin-infra/src/web3/useNameType.ts +++ b/packages/plugin-infra/src/web3/useNameType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useNameType() { - return useWeb3StateContext().nameType + return usePluginWeb3StateContext().nameType } diff --git a/packages/plugin-infra/src/web3/useNetworkType.ts b/packages/plugin-infra/src/web3/useNetworkType.ts index 4f69126b46c1..7d0e02ff7f4d 100644 --- a/packages/plugin-infra/src/web3/useNetworkType.ts +++ b/packages/plugin-infra/src/web3/useNetworkType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useNetworkType() { - return useWeb3StateContext().networkType + return usePluginWeb3StateContext().networkType } diff --git a/packages/plugin-infra/src/web3/useProviderType.ts b/packages/plugin-infra/src/web3/useProviderType.ts index 49ece26362eb..f46346142dff 100644 --- a/packages/plugin-infra/src/web3/useProviderType.ts +++ b/packages/plugin-infra/src/web3/useProviderType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useProviderType() { - return useWeb3StateContext().providerType + return usePluginWeb3StateContext().providerType } diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts index d87b9fa4c0d5..316cf1694123 100644 --- a/packages/plugin-infra/src/web3/useTokenPrice.ts +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -1,7 +1,7 @@ -import { useWeb3StateContext } from '.' import type { Plugin } from '..' +import { usePluginWeb3StateContext } from '../context' export function useTokenPrice(id: string, currencyType: string) { - const { prices } = useWeb3StateContext() ?? {} + const { prices } = usePluginWeb3StateContext() ?? {} return prices?.[id][currencyType as Plugin.Shared.CurrencyType] ?? 0 } diff --git a/packages/plugin-infra/src/web3/useTransactionType.ts b/packages/plugin-infra/src/web3/useTransactionType.ts index cb18ef9a2ee2..875077cdb972 100644 --- a/packages/plugin-infra/src/web3/useTransactionType.ts +++ b/packages/plugin-infra/src/web3/useTransactionType.ts @@ -1,5 +1,5 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useTransactionType() { - return useWeb3StateContext().transactionType + return usePluginWeb3StateContext().transactionType } diff --git a/packages/plugin-infra/src/web3/useWallet.ts b/packages/plugin-infra/src/web3/useWallet.ts index 5ce175591df5..72250601e9ee 100644 --- a/packages/plugin-infra/src/web3/useWallet.ts +++ b/packages/plugin-infra/src/web3/useWallet.ts @@ -1,8 +1,8 @@ import { useAccount } from '.' -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useWallet() { const account = useAccount() - const { wallets } = useWeb3StateContext() + const { wallets } = usePluginWeb3StateContext() return account ? wallets.find((x) => x.address.toLowerCase() === account.toLowerCase()) : undefined } diff --git a/packages/plugin-infra/src/web3/useWalletPrimary.ts b/packages/plugin-infra/src/web3/useWalletPrimary.ts index 270a455b7b4d..4955f20ddc96 100644 --- a/packages/plugin-infra/src/web3/useWalletPrimary.ts +++ b/packages/plugin-infra/src/web3/useWalletPrimary.ts @@ -1,6 +1,6 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useWalletPrimary() { - const { walletPrimary } = useWeb3StateContext() + const { walletPrimary } = usePluginWeb3StateContext() return walletPrimary } diff --git a/packages/plugin-infra/src/web3/useWallets.ts b/packages/plugin-infra/src/web3/useWallets.ts index 5b379d8b2765..6f7c16040536 100644 --- a/packages/plugin-infra/src/web3/useWallets.ts +++ b/packages/plugin-infra/src/web3/useWallets.ts @@ -1,6 +1,6 @@ -import { useWeb3StateContext } from '.' +import { usePluginWeb3StateContext } from '../context' export function useWallets(type?: string) { - const { wallets } = useWeb3StateContext() + const { wallets } = usePluginWeb3StateContext() return wallets } From ff981fcb3438937d9909bda82219432b8aa3757b Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 21:29:33 +0800 Subject: [PATCH 16/41] fix: typo --- packages/plugin-infra/src/types.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 9376235ad063..1ebbf5053f07 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -340,11 +340,11 @@ export namespace Plugin.Shared { export interface Web3Context { Shared?: { allowTestnet: Subscription - /** The ID of currently choosen sub-network. */ + /** The ID of currently chosen sub-network. */ chainId: Subscription - /** The address of the currently choosen wallet. */ + /** The address of the currently chosen wallet. */ account: Subscription - /** The balance of the currently choosen account. */ + /** The balance of the currently chosen account. */ balance: Subscription /** The currently tracked block height. */ blockNumber: Subscription @@ -442,7 +442,7 @@ export namespace Plugin.SNSAdaptor { GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UI?: Shared.Web3UI - /** This is the context of the currently choosen network. */ + /** This is the context of the currently chosen network. */ Web3Context?: Shared.Web3Context /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry @@ -536,7 +536,7 @@ export namespace Plugin.Dashboard { GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UI?: Shared.Web3UI - /** This is the context of the currently choosen network. */ + /** This is the context of the currently chosen network. */ Web3Context?: Shared.Web3Context } } From 370154e10e3c40450f5e65528b1590154114132d Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 8 Nov 2021 23:21:29 +0800 Subject: [PATCH 17/41] refactor: EVM web3 context --- packages/dashboard/src/initialization/Dashboard.tsx | 2 ++ packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx | 2 ++ packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx | 2 ++ packages/mask/src/plugins/EVM/UI/Web3Context/index.ts | 3 +++ packages/mask/src/web3/context.ts | 2 +- packages/plugins/Flow/src/UI/Dashboard/index.tsx | 2 ++ packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx | 2 ++ packages/plugins/Flow/src/UI/Web3Context/index.ts | 3 +++ 8 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 packages/mask/src/plugins/EVM/UI/Web3Context/index.ts create mode 100644 packages/plugins/Flow/src/UI/Web3Context/index.ts diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index 8bf972605672..39346a3e7e72 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -45,6 +45,8 @@ export default function DashboardRoot() { applyMaskColorVars(document.body, appearance === 'default' ? mode : appearance) //#endregion + if (!PluginWeb3Context) return null + return ( diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index edc71f6a55fe..b46e9f1f84c7 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,11 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' +import { Web3Context } from '../Web3Context' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, + Web3Context, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index edc71f6a55fe..b46e9f1f84c7 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,11 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' +import { Web3Context } from '../Web3Context' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, + Web3Context, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts b/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts new file mode 100644 index 000000000000..51a3c2895fed --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts @@ -0,0 +1,3 @@ +import type { Plugin } from '@masknet/plugin-infra' + +export const Web3Context: Plugin.Shared.Web3Context = {} diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 4b9405322db5..2d743f261a24 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -93,8 +93,8 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy getAssetsList: WalletRPC.getAssetsList, getAssetsListNFT: WalletRPC.getAssetsListNFT, getAddressNamesList: WalletRPC.getAddressNames, - fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, getTransactionList: WalletRPC.getTransactionList, + fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, } } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index 9c9587f1417c..0720521c88f4 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,11 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' import { Web3UI } from '../Web3UI' +import { Web3Context } from '../Web3Context' const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, Web3UI, + Web3Context, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index edc71f6a55fe..b46e9f1f84c7 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,11 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' +import { Web3Context } from '../Web3Context' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, + Web3Context, } export default sns diff --git a/packages/plugins/Flow/src/UI/Web3Context/index.ts b/packages/plugins/Flow/src/UI/Web3Context/index.ts new file mode 100644 index 000000000000..51a3c2895fed --- /dev/null +++ b/packages/plugins/Flow/src/UI/Web3Context/index.ts @@ -0,0 +1,3 @@ +import type { Plugin } from '@masknet/plugin-infra' + +export const Web3Context: Plugin.Shared.Web3Context = {} From ac6f09c9c73cb3d234491b25c0ed317ba846a84d Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 9 Nov 2021 15:57:01 +0800 Subject: [PATCH 18/41] fix: context error --- packages/dashboard/src/initialization/Dashboard.tsx | 2 +- packages/plugin-infra/src/context/index.tsx | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index 39346a3e7e72..b7df4a23845f 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -50,7 +50,7 @@ export default function DashboardRoot() { return ( - + diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 119e2b02ca03..2bf8ef61ab7f 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -18,13 +18,15 @@ const EMPTY_ARRAY = createSubscription([]) const FALSE = createSubscription(false) const NULL = createSubscription(null) +const PluginWeb3Context = createContext(null!) + function usePluginWeb3Context() { const context = useContext(PluginWeb3Context) if (!context) throw new Error('This hook should be used in a provider.') return context } -export function usePluginWeb3State() { +function usePluginWeb3State() { const { Shared, Utils } = usePluginWeb3Context() const allowTestnet = useSubscription(Shared?.allowTestnet ?? FALSE) const chainId = useSubscription(Shared?.chainId ?? ZERO) @@ -37,9 +39,7 @@ export function usePluginWeb3State() { const nameType = useSubscription(Shared?.nameType ?? EMPTY_STRING) const collectibleType = useSubscription(Shared?.collectibleType ?? EMPTY_STRING) const transactionType = useSubscription(Shared?.transactionType ?? EMPTY_STRING) - const currencyType = useSubscription( - Shared?.currencyType ?? createSubscription('usd' as Plugin.Shared.CurrencyType), - ) + const currencyType = useSubscription(Shared?.currencyType ?? EMPTY_STRING) const prices = useSubscription(Shared?.prices ?? NULL) const walletPrimary = useSubscription(Shared?.walletPrimary ?? NULL) const wallets = useSubscription(Shared?.wallets ?? EMPTY_ARRAY) @@ -69,7 +69,6 @@ export function usePluginWeb3State() { } } -export const PluginWeb3Context = createContext(null!) export const PluginWeb3StateContext = createContainer(usePluginWeb3State) export const usePluginWeb3StateContext = PluginWeb3StateContext.useContainer From faccc156d1f8abe35950c4bca11c98d34f0d9cfd Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 9 Nov 2021 20:40:56 +0800 Subject: [PATCH 19/41] refactor: combine multiple contexts --- .../src/initialization/Dashboard.tsx | 12 +- .../src/plugins/EVM/UI/Dashboard/index.tsx | 4 +- .../src/plugins/EVM/UI/SNSAdaptor/index.tsx | 4 +- .../src/plugins/EVM/UI/Web3Context/index.ts | 3 - .../src/plugins/EVM/UI/Web3State/index.ts | 3 + .../mask/src/plugins/EVM/UI/Web3UI/index.tsx | 5 - .../PluginNetworkWatcher.tsx | 6 +- .../SNSAdaptor/SelectProviderDialog/index.tsx | 26 +- packages/plugin-infra/src/context/index.tsx | 72 +- packages/plugin-infra/src/hooks/index.ts | 3 +- .../hooks/useActivatedPluginWeb3Context.ts | 6 - .../src/hooks/useActivatedPluginWeb3State.ts | 6 + .../src/hooks/useAllPluginsWeb3State.ts | 12 + .../src/hooks/useRegisteredPluginNetwork.ts | 4 +- packages/plugin-infra/src/types.ts | 82 +- packages/plugin-infra/src/utils/index.ts | 1 + .../plugin-infra/src/utils/subscription.ts | 68 + packages/plugin-infra/src/web3/useAccount.ts | 4 +- .../plugin-infra/src/web3/useAllowTestnet.ts | 4 +- .../plugin-infra/src/web3/useAssetType.ts | 4 +- packages/plugin-infra/src/web3/useBalance.ts | 4 +- .../plugin-infra/src/web3/useBlockNumber.ts | 8 +- .../plugin-infra/src/web3/useChainDetailed.ts | 4 +- packages/plugin-infra/src/web3/useChainId.ts | 12 +- .../src/web3/useCollectibleType.ts | 4 +- .../plugin-infra/src/web3/useCurrencyType.ts | 4 +- packages/plugin-infra/src/web3/useNameType.ts | 4 +- .../plugin-infra/src/web3/useNetworkType.ts | 4 +- .../plugin-infra/src/web3/useProviderType.ts | 4 +- .../plugin-infra/src/web3/useTokenPrice.ts | 4 +- .../src/web3/useTransactionType.ts | 4 +- packages/plugin-infra/src/web3/useWallet.ts | 6 +- .../plugin-infra/src/web3/useWalletPrimary.ts | 5 +- packages/plugin-infra/src/web3/useWallets.ts | 5 +- packages/plugins/Flow/package.json | 2 + .../plugins/Flow/src/UI/Dashboard/index.tsx | 4 +- .../plugins/Flow/src/UI/SNSAdaptor/index.tsx | 4 +- .../plugins/Flow/src/UI/Web3Context/index.ts | 3 - .../plugins/Flow/src/UI/Web3State/index.ts | 53 + packages/plugins/Flow/src/UI/Web3UI/index.tsx | 12 - packages/plugins/Flow/src/env.d.ts | 34 + packages/plugins/Flow/src/messages.ts | 1 - packages/web3-constants/flow/auth.json | 8 + packages/web3-shared/flow/hooks/index.ts | 2 - .../web3-shared/flow/hooks/useNetworkType.ts | 7 - .../web3-shared/flow/hooks/useProviderType.ts | 5 - pnpm-lock.yaml | 1089 +++++++---------- 47 files changed, 824 insertions(+), 801 deletions(-) delete mode 100644 packages/mask/src/plugins/EVM/UI/Web3Context/index.ts create mode 100644 packages/mask/src/plugins/EVM/UI/Web3State/index.ts delete mode 100644 packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts create mode 100644 packages/plugin-infra/src/hooks/useActivatedPluginWeb3State.ts create mode 100644 packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts create mode 100644 packages/plugin-infra/src/utils/subscription.ts delete mode 100644 packages/plugins/Flow/src/UI/Web3Context/index.ts create mode 100644 packages/plugins/Flow/src/UI/Web3State/index.ts delete mode 100644 packages/web3-shared/flow/hooks/useNetworkType.ts delete mode 100644 packages/web3-shared/flow/hooks/useProviderType.ts diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index b7df4a23845f..f51def04bc9f 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -11,9 +11,9 @@ import { import { ErrorBoundary } from '@masknet/shared' import { createInjectHooksRenderer, - PluginWeb3ContextProvider, + PluginsWeb3ContextProvider, useActivatedPluginsDashboard, - useActivatedPluginWeb3Context, + useAllPluginsWeb3State, } from '@masknet/plugin-infra' import { Web3Provider } from '@masknet/web3-shared-evm' @@ -30,7 +30,7 @@ const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) export default function DashboardRoot() { const pluginID = usePluginID() - const PluginWeb3Context = useActivatedPluginWeb3Context(pluginID) + const PluginsWeb3State = useAllPluginsWeb3State() //#region theme const appearance = useAppearance() @@ -45,12 +45,12 @@ export default function DashboardRoot() { applyMaskColorVars(document.body, appearance === 'default' ? mode : appearance) //#endregion - if (!PluginWeb3Context) return null + if (!PluginsWeb3State) return null return ( - + @@ -68,7 +68,7 @@ export default function DashboardRoot() { - + ) diff --git a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx index b46e9f1f84c7..160d09fc0709 100644 --- a/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Dashboard/index.tsx @@ -1,13 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' -import { Web3Context } from '../Web3Context' +import { Web3State } from '../Web3State' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, - Web3Context, + Web3State, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx index b46e9f1f84c7..160d09fc0709 100644 --- a/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/SNSAdaptor/index.tsx @@ -1,13 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' -import { Web3Context } from '../Web3Context' +import { Web3State } from '../Web3State' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, - Web3Context, + Web3State, } export default sns diff --git a/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts b/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts deleted file mode 100644 index 51a3c2895fed..000000000000 --- a/packages/mask/src/plugins/EVM/UI/Web3Context/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Plugin } from '@masknet/plugin-infra' - -export const Web3Context: Plugin.Shared.Web3Context = {} diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts new file mode 100644 index 000000000000..a4107c3fecb3 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -0,0 +1,3 @@ +import type { Plugin } from '@masknet/plugin-infra' + +export const Web3State: Plugin.Shared.Web3State = {} diff --git a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx index bafbdeec7939..4982f2d52a6b 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx @@ -1,12 +1,7 @@ import type { Plugin } from '@masknet/plugin-infra' -import { useNetwork, useProvider } from '../../hooks' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' export const Web3UI: Plugin.Shared.Web3UI = { - Shared: { - useNetwork, - useProvider, - }, SelectProviderDialog: { ProviderIconClickBait, }, diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx index bf70655bca69..2b7cb048d53b 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx @@ -3,14 +3,12 @@ import { useEffect } from 'react' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' export interface PluginNetworkWatcherProps { - useNetwork: () => Plugin.Shared.Network | null + network?: Plugin.Shared.Network expectedPluginID: string expectedNetworkID: string } -export function PluginNetworkWatcher({ useNetwork, expectedPluginID, expectedNetworkID }: PluginNetworkWatcherProps) { - const network = useNetwork() - +export function PluginNetworkWatcher({ network, expectedPluginID, expectedNetworkID }: PluginNetworkWatcherProps) { useEffect(() => { const matched = network && network.pluginID === expectedPluginID && network.ID === expectedNetworkID if (!matched) return diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 6a9165e3337e..cfda21f310ff 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -9,7 +9,13 @@ import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' -import { useRegisteredNetworks, useRegisteredProviders, useActivatedPluginWeb3UI } from '@masknet/plugin-infra' +import { + useRegisteredNetworks, + useRegisteredProviders, + useActivatedPluginWeb3UI, + useNetworkType, + useRegisteredPluginNetwork, +} from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ content: { @@ -43,13 +49,23 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) + const undeterminedWeb3UI = useActivatedPluginWeb3UI(undeterminedPluginID) + const undeterminedNetworkType = useNetworkType(undeterminedPluginID) + const undeterminedNetwork = useRegisteredPluginNetwork(undeterminedPluginID, undeterminedNetworkType) + const networks = useRegisteredNetworks() const providers = useRegisteredProviders() - const Web3UI = useActivatedPluginWeb3UI(pluginID) + console.log({ + pluginID, + networkID, + undeterminedPluginID, + undeterminedNetworkID, + undeterminedNetwork, + undeterminedNetworkType, + }) - const { useNetwork = () => null } = Web3UI?.Shared ?? {} - const { NetworkIconClickBait, ProviderIconClickBait } = Web3UI?.SelectProviderDialog ?? {} + const { NetworkIconClickBait, ProviderIconClickBait } = undeterminedWeb3UI?.SelectProviderDialog ?? {} // not available for the native app if (hasNativeAPI) return null @@ -58,7 +74,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { if (!open) return ( diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 2bf8ef61ab7f..8528fe6a69e5 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -1,33 +1,36 @@ -import { noop } from 'lodash-es' import React, { createContext, useContext } from 'react' import { createContainer } from 'unstated-next' import { useSubscription } from 'use-subscription' import type { Plugin } from '..' +import { createConstantSubscription } from '../utils' -function createSubscription(value: T) { - return { - getCurrentValue: () => value, - subscribe: () => noop, - } -} +// network plugins +const PLUGIN_EVM_ID = 'com.maskbook.evm' +const PLUGIN_FLOW_ID = 'com.maskbook.flow' -const ZERO = createSubscription(0) -const ZERO_STRING = createSubscription('0') -const EMPTY_STRING = createSubscription('') -const EMPTY_ARRAY = createSubscription([]) -const FALSE = createSubscription(false) -const NULL = createSubscription(null) +// constant subscriptions +const ZERO = createConstantSubscription(0) +const ZERO_STRING = createConstantSubscription('0') +const EMPTY_STRING = createConstantSubscription('') +const EMPTY_ARRAY = createConstantSubscription([]) +const FALSE = createConstantSubscription(false) +const NULL = createConstantSubscription(null) -const PluginWeb3Context = createContext(null!) +const PluginIDContext = createContext(PLUGIN_EVM_ID) -function usePluginWeb3Context() { - const context = useContext(PluginWeb3Context) +const PluginsWeb3Context = createContext>(null!) + +function usePluginsWeb3Context() { + const context = useContext(PluginsWeb3Context) if (!context) throw new Error('This hook should be used in a provider.') return context } -function usePluginWeb3State() { - const { Shared, Utils } = usePluginWeb3Context() +function usePluginWeb3State(pluginID: string, context: Record) { + const pluginContext = context[pluginID] + if (!pluginContext) throw new Error(`The context of ${pluginID} is undefined.`) + + const { Shared, Utils } = pluginContext const allowTestnet = useSubscription(Shared?.allowTestnet ?? FALSE) const chainId = useSubscription(Shared?.chainId ?? ZERO) const account = useSubscription(Shared?.account ?? EMPTY_STRING) @@ -69,14 +72,35 @@ function usePluginWeb3State() { } } -export const PluginWeb3StateContext = createContainer(usePluginWeb3State) +function usePluginsWeb3State() { + const context = usePluginsWeb3Context() + return { + [PLUGIN_EVM_ID]: usePluginWeb3State(PLUGIN_EVM_ID, context), + [PLUGIN_FLOW_ID]: usePluginWeb3State(PLUGIN_FLOW_ID, context), + } +} + +const PluginsWeb3StateContext = createContainer(usePluginsWeb3State) -export const usePluginWeb3StateContext = PluginWeb3StateContext.useContainer +export const usePluginsWeb3StateContext = PluginsWeb3StateContext.useContainer + +export function usePluginWeb3StateContext(expectedPluginID?: string) { + const pluginID = useContext(PluginIDContext) + const pluginsWeb3State = usePluginsWeb3StateContext() + // @ts-ignore + return pluginsWeb3State[expectedPluginID ?? pluginID] as ReturnType +} -export function PluginWeb3ContextProvider({ value, children }: React.ProviderProps) { +export function PluginsWeb3ContextProvider({ + pluginID, + value, + children, +}: { pluginID: string } & React.ProviderProps>) { return ( - - {children} - + + + {children} + + ) } diff --git a/packages/plugin-infra/src/hooks/index.ts b/packages/plugin-infra/src/hooks/index.ts index 1a907e896d5a..150490d43fb9 100644 --- a/packages/plugin-infra/src/hooks/index.ts +++ b/packages/plugin-infra/src/hooks/index.ts @@ -1,6 +1,7 @@ export * from './useActivatedPlugin' export * from './useActivatedPluginWeb3UI' -export * from './useActivatedPluginWeb3Context' +export * from './useActivatedPluginWeb3State' +export * from './useAllPluginsWeb3State' export * from './useRegisteredPlugin' export * from './useRegisteredPluginNetwork' export * from './useRegisteredPluginProvider' diff --git a/packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts deleted file mode 100644 index 3f0b52ee38c8..000000000000 --- a/packages/plugin-infra/src/hooks/useActivatedPluginWeb3Context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useActivatedPlugin } from '.' - -export function useActivatedPluginWeb3Context(pluginID: string) { - const activatedPlugin = useActivatedPlugin(pluginID) - return activatedPlugin?.Web3Context ?? null -} diff --git a/packages/plugin-infra/src/hooks/useActivatedPluginWeb3State.ts b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3State.ts new file mode 100644 index 000000000000..1acbec630b13 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useActivatedPluginWeb3State.ts @@ -0,0 +1,6 @@ +import { useActivatedPlugin } from '.' + +export function useActivatedPluginWeb3State(pluginID: string) { + const activatedPlugin = useActivatedPlugin(pluginID) + return activatedPlugin?.Web3State ?? null +} diff --git a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts new file mode 100644 index 000000000000..569a9e6d1375 --- /dev/null +++ b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts @@ -0,0 +1,12 @@ +import { Plugin, useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor } from '..' + +export function useAllPluginsWeb3State() { + const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() + const pluginsDashboard = useActivatedPluginsDashboard() + return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce((accumulator, current) => { + if (current.Web3State) { + accumulator[current.ID] = current.Web3State + } + return accumulator + }, {} as Record) +} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts index d26806c0be29..77dc42e205a9 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts @@ -1,5 +1,5 @@ import { useRegisteredPlugin } from '.' -export function useRegisteredPluginNetwork(pluginID: string, networkID: string) { - return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.ID === networkID) +export function useRegisteredPluginNetwork(pluginID: string, networkType?: string) { + return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.type === networkType) } diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 1ebbf5053f07..bc1082ece5a4 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -199,12 +199,6 @@ export namespace Plugin.Shared { } export interface Web3UI { - Shared?: { - /** A react hook returns the currently selected provider. */ - useProvider?: () => Shared.Provider | null - /** A react hook returns the currently selected network. */ - useNetwork?: () => Shared.Network | null - } SelectProviderDialog?: { /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> @@ -337,94 +331,94 @@ export namespace Plugin.Shared { tokens: Token[] } - export interface Web3Context { + export interface Web3State { Shared?: { - allowTestnet: Subscription + allowTestnet?: Subscription /** The ID of currently chosen sub-network. */ - chainId: Subscription + chainId?: Subscription /** The address of the currently chosen wallet. */ - account: Subscription + account?: Subscription /** The balance of the currently chosen account. */ - balance: Subscription + balance?: Subscription /** The currently tracked block height. */ - blockNumber: Subscription + blockNumber?: Subscription /** The network type. */ - networkType: Subscription + networkType?: Subscription /** The wallet provider type. */ - providerType: Subscription + providerType?: Subscription /** The asset data provider. */ - assetType: Subscription + assetType?: Subscription /** The address name data provider. */ - nameType: Subscription + nameType?: Subscription /** The collectible data provider. */ - collectibleType: Subscription + collectibleType?: Subscription /** The transaction data provider. */ - transactionType: Subscription + transactionType?: Subscription /** The currency of estimated values and prices. */ - currencyType: Subscription + currencyType?: Subscription /** The tracked token prices which stored as address and price pairs. */ - prices: Subscription + prices?: Subscription /** The currently stored wallet by MaskWallet. */ - wallets: Subscription + wallets?: Subscription /** The default derivable wallet. */ - walletPrimary: Subscription + walletPrimary?: Subscription /** The user added fungible tokens. */ - fungibleTokens: Subscription[]> + fungibleTokens?: Subscription[]> /** The user added non-fungible tokens. */ - nonFungibleTokens: Subscription[]> + nonFungibleTokens?: Subscription[]> } Asset?: { /** Get fungible assets of given account. */ - getFungibleAssets( + getFungibleAssets?: ( address: string, providerType: string, networkType: string, pagination?: Pagination, - ): Promise[]> + ) => Promise[]> /** Get non-fungible assets of given account. */ - getNonFungibleAssets( + getNonFungibleAssets: ( address: string, providerType: string, networkType: string, pagination?: Pagination, - ): Promise[]> + ) => Promise[]> } Token?: { - addToken(token: Token): Promise - removeToken(token: Token): Promise - trustToken(token: Token): Promise - blockToken(token: Token): Promise + addToken: (token: Token) => Promise + removeToken: (token: Token) => Promise + trustToken: (token: Token) => Promise + blockToken: (token: Token) => Promise } Transaction?: { /** Get latest transactions of given account. */ - getTransactions( + getTransactions: ( address: string, providerType: string, networkType: string, pagination?: Pagination, - ): Promise + ) => Promise } TokenList?: { /** Get the token lists of supported fungible tokens. */ - getFungibleTokenLists( + getFungibleTokenLists: ( address: string, providerType: string, networkType: string, pagination?: Pagination, - ): Promise[]> + ) => Promise[]> /** Get the token lists of supported non-fungible tokens. */ - getNonFungibleTokenLists( + getNonFungibleTokenLists: ( address: string, providerType: string, networkType: string, pagination?: Pagination, - ): Promise[]> + ) => Promise[]> } Utils?: { - isChainIdValid(chainId: number, allowTestnet: boolean): boolean - getChainDetailed(chainId: number): ChainDetailed - getFungibleTokenMetadata(token: Token): Promise> - getNonFungibleTokenMetadata(token: Token): Promise> + isChainIdValid: (chainId: number, allowTestnet: boolean) => boolean + getChainDetailed: (chainId: number) => ChainDetailed + getFungibleTokenMetadata: (token: Token) => Promise> + getNonFungibleTokenMetadata: (token: Token) => Promise> } } } @@ -443,7 +437,7 @@ export namespace Plugin.SNSAdaptor { /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UI?: Shared.Web3UI /** This is the context of the currently chosen network. */ - Web3Context?: Shared.Web3Context + Web3State?: Shared.Web3State /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -537,7 +531,7 @@ export namespace Plugin.Dashboard { /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ Web3UI?: Shared.Web3UI /** This is the context of the currently chosen network. */ - Web3Context?: Shared.Web3Context + Web3State?: Shared.Web3State } } diff --git a/packages/plugin-infra/src/utils/index.ts b/packages/plugin-infra/src/utils/index.ts index 091067f16c38..cfea07dfa23b 100644 --- a/packages/plugin-infra/src/utils/index.ts +++ b/packages/plugin-infra/src/utils/index.ts @@ -1,3 +1,4 @@ export { createInjectHooksRenderer } from './createInjectHooksRenderer' export * from './message' export * from './rpc' +export * from './subscription' diff --git a/packages/plugin-infra/src/utils/subscription.ts b/packages/plugin-infra/src/utils/subscription.ts new file mode 100644 index 000000000000..3d155c4bc9e3 --- /dev/null +++ b/packages/plugin-infra/src/utils/subscription.ts @@ -0,0 +1,68 @@ +import { noop } from 'lodash-es' +import type { Subscription } from 'use-subscription' + +export function createStaticSubscription(getter: () => T) { + return { + getCurrentValue: getter, + subscribe: () => noop, + } +} + +export function createConstantSubscription(value: T) { + return { + getCurrentValue: () => value, + subscribe: () => noop, + } +} + +export function createSubscriptionFromAsync( + f: () => Promise, + defaultValue: T, + onChange: (callback: () => void) => () => void, +): Subscription { + // 0 - idle, 1 - updating state, > 1 - waiting state + let beats = 0 + let state = defaultValue + const { subscribe, trigger } = getEventTarget() + f() + .then((v) => (state = v)) + .finally(trigger) + const flush = async () => { + state = await f() + beats -= 1 + if (beats > 0) { + beats = 1 + setTimeout(flush, 0) + } else if (beats < 0) { + beats = 0 + } + trigger() + } + return { + getCurrentValue: () => state, + subscribe: (sub) => { + const a = subscribe(sub) + const b = onChange(async () => { + beats += 1 + if (beats === 1) flush() + }) + return () => void [a(), b()] + }, + } +} + +function getEventTarget() { + const event = new EventTarget() + const EVENT = 'event' + let timer: NodeJS.Timeout + function trigger() { + clearTimeout(timer) + // delay to update state to ensure that all settings to be synced globally + timer = setTimeout(() => event.dispatchEvent(new Event(EVENT)), 600) + } + function subscribe(f: () => void) { + event.addEventListener(EVENT, f) + return () => event.removeEventListener(EVENT, f) + } + return { trigger, subscribe } +} diff --git a/packages/plugin-infra/src/web3/useAccount.ts b/packages/plugin-infra/src/web3/useAccount.ts index 75cd39e97a5a..c6195739dc45 100644 --- a/packages/plugin-infra/src/web3/useAccount.ts +++ b/packages/plugin-infra/src/web3/useAccount.ts @@ -4,7 +4,7 @@ import { usePluginWeb3StateContext } from '../context' /** * Get the address of the default wallet */ -export function useAccount() { - const { account, wallets } = usePluginWeb3StateContext() +export function useAccount(pluginID?: string) { + const { account, wallets } = usePluginWeb3StateContext(pluginID) return process.env.architecture === 'app' ? first(wallets)?.address ?? '' : account } diff --git a/packages/plugin-infra/src/web3/useAllowTestnet.ts b/packages/plugin-infra/src/web3/useAllowTestnet.ts index 09bf809bf918..ff5371c7c0a4 100644 --- a/packages/plugin-infra/src/web3/useAllowTestnet.ts +++ b/packages/plugin-infra/src/web3/useAllowTestnet.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useAllowTestnet() { - return usePluginWeb3StateContext().allowTestnet +export function useAllowTestnet(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).allowTestnet } diff --git a/packages/plugin-infra/src/web3/useAssetType.ts b/packages/plugin-infra/src/web3/useAssetType.ts index c386d1725d66..636f75a58cf7 100644 --- a/packages/plugin-infra/src/web3/useAssetType.ts +++ b/packages/plugin-infra/src/web3/useAssetType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useAssetType() { - return usePluginWeb3StateContext().assetType +export function useAssetType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).assetType } diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts index 3d5339db8494..ed23058462ff 100644 --- a/packages/plugin-infra/src/web3/useBalance.ts +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -3,6 +3,6 @@ import { usePluginWeb3StateContext } from '../context' /** * Get the current block number */ -export function useBalance() { - return usePluginWeb3StateContext().balance +export function useBalance(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).balance } diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index ee723acf455f..2e47e9acca5f 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -4,16 +4,16 @@ import { usePluginWeb3StateContext } from '../context' /** * Get the current block number of current chain */ -export function useBlockNumber() { - return usePluginWeb3StateContext().blockNumber +export function useBlockNumber(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).blockNumber } /** * Get the current block number only once * @returns */ -export function useBlockNumberOnce() { - const blockNumber = useBlockNumber() +export function useBlockNumberOnce(pluginID?: string) { + const blockNumber = useBlockNumber(pluginID) const [blockNumberOnce, setBlockNumberOnce] = useState(0) useEffect(() => { if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) diff --git a/packages/plugin-infra/src/web3/useChainDetailed.ts b/packages/plugin-infra/src/web3/useChainDetailed.ts index eb8d0338033c..142184f0e802 100644 --- a/packages/plugin-infra/src/web3/useChainDetailed.ts +++ b/packages/plugin-infra/src/web3/useChainDetailed.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useChainDetailed() { - return usePluginWeb3StateContext().chainDetailed +export function useChainDetailed(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).chainDetailed } diff --git a/packages/plugin-infra/src/web3/useChainId.ts b/packages/plugin-infra/src/web3/useChainId.ts index 56c47dff0b3a..9bf633b9e6f0 100644 --- a/packages/plugin-infra/src/web3/useChainId.ts +++ b/packages/plugin-infra/src/web3/useChainId.ts @@ -5,15 +5,15 @@ import { usePluginWeb3StateContext } from '../context' * Get the chain id which is using by the given (or default) wallet * It will always yield Mainnet in production mode */ -export function useChainId() { - return usePluginWeb3StateContext().chainId +export function useChainId(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).chainId } /** * Returns true if chain id is available */ -export function useChainIdValid() { - return usePluginWeb3StateContext().chainIdValid +export function useChainIdValid(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).chainIdValid } /** @@ -21,8 +21,8 @@ export function useChainIdValid() { * @param chainId * @returns */ -export function useChainIdMatched(chainId?: number) { - const chainDetailed = useChainDetailed() +export function useChainIdMatched(pluginID?: string, chainId?: number) { + const chainDetailed = useChainDetailed(pluginID) if (!chainId) return false return chainDetailed?.chainId === chainId } diff --git a/packages/plugin-infra/src/web3/useCollectibleType.ts b/packages/plugin-infra/src/web3/useCollectibleType.ts index 4ef3b6bc556d..810927d5205e 100644 --- a/packages/plugin-infra/src/web3/useCollectibleType.ts +++ b/packages/plugin-infra/src/web3/useCollectibleType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useCollectibleType() { - return usePluginWeb3StateContext().collectibleType +export function useCollectibleType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).collectibleType } diff --git a/packages/plugin-infra/src/web3/useCurrencyType.ts b/packages/plugin-infra/src/web3/useCurrencyType.ts index 18d1f466ac0e..f174b469bdae 100644 --- a/packages/plugin-infra/src/web3/useCurrencyType.ts +++ b/packages/plugin-infra/src/web3/useCurrencyType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useCurrencyType() { - return usePluginWeb3StateContext().currencyType +export function useCurrencyType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).currencyType } diff --git a/packages/plugin-infra/src/web3/useNameType.ts b/packages/plugin-infra/src/web3/useNameType.ts index 0a4c906babf7..8b1b1bb3ea73 100644 --- a/packages/plugin-infra/src/web3/useNameType.ts +++ b/packages/plugin-infra/src/web3/useNameType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useNameType() { - return usePluginWeb3StateContext().nameType +export function useNameType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).nameType } diff --git a/packages/plugin-infra/src/web3/useNetworkType.ts b/packages/plugin-infra/src/web3/useNetworkType.ts index 7d0e02ff7f4d..789238ecabc6 100644 --- a/packages/plugin-infra/src/web3/useNetworkType.ts +++ b/packages/plugin-infra/src/web3/useNetworkType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useNetworkType() { - return usePluginWeb3StateContext().networkType +export function useNetworkType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).networkType } diff --git a/packages/plugin-infra/src/web3/useProviderType.ts b/packages/plugin-infra/src/web3/useProviderType.ts index f46346142dff..6d39df26a938 100644 --- a/packages/plugin-infra/src/web3/useProviderType.ts +++ b/packages/plugin-infra/src/web3/useProviderType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useProviderType() { - return usePluginWeb3StateContext().providerType +export function useProviderType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).providerType } diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts index 316cf1694123..415f47d749a3 100644 --- a/packages/plugin-infra/src/web3/useTokenPrice.ts +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -1,7 +1,7 @@ import type { Plugin } from '..' import { usePluginWeb3StateContext } from '../context' -export function useTokenPrice(id: string, currencyType: string) { - const { prices } = usePluginWeb3StateContext() ?? {} +export function useTokenPrice(id: string, currencyType: string, pluginID?: string) { + const { prices } = usePluginWeb3StateContext(pluginID) ?? {} return prices?.[id][currencyType as Plugin.Shared.CurrencyType] ?? 0 } diff --git a/packages/plugin-infra/src/web3/useTransactionType.ts b/packages/plugin-infra/src/web3/useTransactionType.ts index 875077cdb972..c08283474f26 100644 --- a/packages/plugin-infra/src/web3/useTransactionType.ts +++ b/packages/plugin-infra/src/web3/useTransactionType.ts @@ -1,5 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useTransactionType() { - return usePluginWeb3StateContext().transactionType +export function useTransactionType(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).transactionType } diff --git a/packages/plugin-infra/src/web3/useWallet.ts b/packages/plugin-infra/src/web3/useWallet.ts index 72250601e9ee..5086bcae0a42 100644 --- a/packages/plugin-infra/src/web3/useWallet.ts +++ b/packages/plugin-infra/src/web3/useWallet.ts @@ -1,8 +1,8 @@ import { useAccount } from '.' import { usePluginWeb3StateContext } from '../context' -export function useWallet() { - const account = useAccount() - const { wallets } = usePluginWeb3StateContext() +export function useWallet(pluginID?: string) { + const account = useAccount(pluginID) + const { wallets } = usePluginWeb3StateContext(pluginID) return account ? wallets.find((x) => x.address.toLowerCase() === account.toLowerCase()) : undefined } diff --git a/packages/plugin-infra/src/web3/useWalletPrimary.ts b/packages/plugin-infra/src/web3/useWalletPrimary.ts index 4955f20ddc96..a83a6ec85a3f 100644 --- a/packages/plugin-infra/src/web3/useWalletPrimary.ts +++ b/packages/plugin-infra/src/web3/useWalletPrimary.ts @@ -1,6 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useWalletPrimary() { - const { walletPrimary } = usePluginWeb3StateContext() - return walletPrimary +export function useWalletPrimary(pluginID?: string) { + return usePluginWeb3StateContext(pluginID).walletPrimary } diff --git a/packages/plugin-infra/src/web3/useWallets.ts b/packages/plugin-infra/src/web3/useWallets.ts index 6f7c16040536..ff13acb9163a 100644 --- a/packages/plugin-infra/src/web3/useWallets.ts +++ b/packages/plugin-infra/src/web3/useWallets.ts @@ -1,6 +1,5 @@ import { usePluginWeb3StateContext } from '../context' -export function useWallets(type?: string) { - const { wallets } = usePluginWeb3StateContext() - return wallets +export function useWallets(type?: string, pluginID?: string) { + return usePluginWeb3StateContext(pluginID).wallets } diff --git a/packages/plugins/Flow/package.json b/packages/plugins/Flow/package.json index a810f50e98e5..5de8d597f4a8 100644 --- a/packages/plugins/Flow/package.json +++ b/packages/plugins/Flow/package.json @@ -10,7 +10,9 @@ "@masknet/shared-base": "workspace:*", "@masknet/theme": "workspace:*", "@masknet/web3-shared-flow": "workspace:*", + "@onflow/fcl": "^0.0.77", "bignumber.js": "^9.0.1", + "lodash-es": "^4.17.21", "react-use": "^17.3.1" } } diff --git a/packages/plugins/Flow/src/UI/Dashboard/index.tsx b/packages/plugins/Flow/src/UI/Dashboard/index.tsx index 0720521c88f4..c4eac6cb254e 100644 --- a/packages/plugins/Flow/src/UI/Dashboard/index.tsx +++ b/packages/plugins/Flow/src/UI/Dashboard/index.tsx @@ -1,13 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra/src' import { base } from '../../base' import { Web3UI } from '../Web3UI' -import { Web3Context } from '../Web3Context' +import { Web3State } from '../Web3State' const sns: Plugin.Dashboard.Definition = { ...base, init(signal) {}, Web3UI, - Web3Context, + Web3State, } export default sns diff --git a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx index b46e9f1f84c7..160d09fc0709 100644 --- a/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx +++ b/packages/plugins/Flow/src/UI/SNSAdaptor/index.tsx @@ -1,13 +1,13 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../../base' import { Web3UI } from '../Web3UI' -import { Web3Context } from '../Web3Context' +import { Web3State } from '../Web3State' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, Web3UI, - Web3Context, + Web3State, } export default sns diff --git a/packages/plugins/Flow/src/UI/Web3Context/index.ts b/packages/plugins/Flow/src/UI/Web3Context/index.ts deleted file mode 100644 index 51a3c2895fed..000000000000 --- a/packages/plugins/Flow/src/UI/Web3Context/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Plugin } from '@masknet/plugin-infra' - -export const Web3Context: Plugin.Shared.Web3Context = {} diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts new file mode 100644 index 000000000000..4338893b3458 --- /dev/null +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -0,0 +1,53 @@ +import { remove } from 'lodash-es' +import * as fcl from '@onflow/fcl' +import { createConstantSubscription, createSubscriptionFromAsync, Plugin } from '@masknet/plugin-infra' +import { getAuthConstants } from '@masknet/web3-shared-flow/constants' +import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-flow' + +function createClient(chainId: ChainId) { + const authConstants = getAuthConstants(chainId) + + fcl.config({ + 'accessNode.api': authConstants.ACCESS_NODE_API, + 'app.detail.title': authConstants.MASK_APP_TITLE, + 'app.detail.icon': authConstants.MASK_APP_ICON, + 'challenge.handshake': authConstants.CHALLENGE_HANDSHAKE, + }) + return fcl +} + +function createCurrentUserSubscription(chainId: ChainId, fallback: T, getter: (client: typeof fcl) => T) { + const client = createClient(chainId) + const listeners: (() => void)[] = [] + + client.currentUser().subscribe(() => { + listeners.forEach((f) => f()) + }) + + return createSubscriptionFromAsync( + async () => { + return getter(fcl) + }, + fallback, + (sub) => { + listeners.push(sub) + return () => remove(listeners, sub) + }, + ) +} + +function createWeb3State() { + const chainId = ChainId.Testnet + return { + Shared: { + allowTestnet: createConstantSubscription(false), + chainId: createConstantSubscription(chainId), + networkType: createConstantSubscription(NetworkType.Flow), + providerType: createCurrentUserSubscription(chainId, undefined, (client) => { + return client.currentUser().snapshot() ? ProviderType.Blocto : undefined + }), + }, + } +} + +export const Web3State: Plugin.Shared.Web3State = createWeb3State() diff --git a/packages/plugins/Flow/src/UI/Web3UI/index.tsx b/packages/plugins/Flow/src/UI/Web3UI/index.tsx index f391a6ae6504..4982f2d52a6b 100644 --- a/packages/plugins/Flow/src/UI/Web3UI/index.tsx +++ b/packages/plugins/Flow/src/UI/Web3UI/index.tsx @@ -1,19 +1,7 @@ import type { Plugin } from '@masknet/plugin-infra' -import { useNetworkType, useProviderType } from '@masknet/web3-shared-flow' -import { PLUGIN_NETWORKS, PLUGIN_PROVIDERS } from '../../constants' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' export const Web3UI: Plugin.Shared.Web3UI = { - Shared: { - useNetwork() { - const networkType = useNetworkType() - return PLUGIN_NETWORKS.find((x) => x.type === networkType) ?? null - }, - useProvider() { - const providerType = useProviderType() - return PLUGIN_PROVIDERS.find((x) => x.type === providerType) ?? null - }, - }, SelectProviderDialog: { ProviderIconClickBait, }, diff --git a/packages/plugins/Flow/src/env.d.ts b/packages/plugins/Flow/src/env.d.ts index 868322d5ff30..a978ef120540 100644 --- a/packages/plugins/Flow/src/env.d.ts +++ b/packages/plugins/Flow/src/env.d.ts @@ -1 +1,35 @@ /// + +declare module '@onflow/fcl' { + export interface User { + addr: string | null + f_type: 'User' + f_vsn: string + loggedIn: boolean | null + } + + export interface Account { + address: string + balance: string + code: string + } + + export const config: (setup: Record) => {} + export const currentUser: () => { + subscribe: (callback: (user: User) => void) => void + snapshot: () => User + authenticate: () => {} + unauthenticate: () => {} + } + export const subscribe: (callback: (user: User) => void) => void + export const snapshot: () => User + export const authenticate: () => {} + export const unauthenticate: () => {} + export const logIn: () => {} + export const logOut: () => {} + export const signUp: () => {} + + export const send: (data: string[]) => Promise + export const script: (text: string) => string + export const getAccount: (address: string) => string +} diff --git a/packages/plugins/Flow/src/messages.ts b/packages/plugins/Flow/src/messages.ts index 28e50916bf1d..e0da0b8c4ff7 100644 --- a/packages/plugins/Flow/src/messages.ts +++ b/packages/plugins/Flow/src/messages.ts @@ -3,5 +3,4 @@ import { PLUGIN_ID } from './constants' if (import.meta.webpackHot) import.meta.webpackHot.accept() const FlowMessage = createPluginMessage(PLUGIN_ID) - export const FlowRPC = createPluginRPC(PLUGIN_ID, () => import('./services'), FlowMessage.rpc) diff --git a/packages/web3-constants/flow/auth.json b/packages/web3-constants/flow/auth.json index 4696ab57496f..65ad7bd23a6c 100644 --- a/packages/web3-constants/flow/auth.json +++ b/packages/web3-constants/flow/auth.json @@ -10,5 +10,13 @@ "CHALLENGE_HANDSHAKE": { "Mainnet": "https://flow-wallet.blocto.app/authn", "Testnet": "https://flow-wallet-testnet.blocto.app/authn" + }, + "MASK_APP_TITLE": { + "Mainnet": "Mask Network", + "Testnet": "Mask Network (Dev)" + }, + "MASK_APP_ICON": { + "Mainnet": "https://dimensiondev.github.io/Maskbook-VI/assets/Logo/MB--Logo--Geo--ForceCircle--Blue.svg", + "Testnet": "https://dimensiondev.github.io/Maskbook-VI/assets/Logo/MB--Logo--Geo--ForceCircle--Blue.svg" } } diff --git a/packages/web3-shared/flow/hooks/index.ts b/packages/web3-shared/flow/hooks/index.ts index 1a0a7b591570..8128752358cb 100644 --- a/packages/web3-shared/flow/hooks/index.ts +++ b/packages/web3-shared/flow/hooks/index.ts @@ -5,5 +5,3 @@ export * from './useChainConfig' export * from './useCurrentUser' export * from './useFCL' export * from './useScript' -export * from './useNetworkType' -export * from './useProviderType' diff --git a/packages/web3-shared/flow/hooks/useNetworkType.ts b/packages/web3-shared/flow/hooks/useNetworkType.ts deleted file mode 100644 index f35d3fc0e1c9..000000000000 --- a/packages/web3-shared/flow/hooks/useNetworkType.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useCurrentUser } from '.' -import { NetworkType } from '../types' - -export function useNetworkType() { - const currentUser = useCurrentUser() - return currentUser ? NetworkType.Flow : null -} diff --git a/packages/web3-shared/flow/hooks/useProviderType.ts b/packages/web3-shared/flow/hooks/useProviderType.ts deleted file mode 100644 index ed31b3d0f565..000000000000 --- a/packages/web3-shared/flow/hooks/useProviderType.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ProviderType } from '../types' - -export function useProviderType() { - return ProviderType.Blocto -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f07c9c86ce35..21ebfafbe90e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,7 +108,7 @@ importers: '@dimensiondev/kit': ^0.0.0-20210913111737-84c17d7 '@msgpack/msgpack': ^2.7.1 dependencies: - '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_9a9fcfd9691ee39f83ac00f4a3221da4 + '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7 '@msgpack/msgpack': 2.7.1 packages/dashboard: @@ -165,7 +165,7 @@ importers: zod: ^3.11.6 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 - '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_1f3bb381423595cffa34751168edda8e + '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_react-router@6.0.0-beta.4 '@hookform/resolvers': 2.8.3_react-hook-form@7.18.1 '@masknet/backup-format': link:../backup-format '@masknet/icons': link:../icons @@ -191,26 +191,26 @@ importers: i18next-browser-languagedetector: 6.1.2 json-stable-stringify: 1.0.1 lodash-es: 4.17.21 - react-avatar-editor: 12.0.0_23eba1549ad9a79a22241637c0deb6bc - react-hook-form: 7.18.1_c9c210d65bdac3c3f586a38a4275dd8c - react-router: 6.0.0-beta.4_63e1619e79ddca1f1ecc330403c2f112 - react-router-dom: 6.0.0-beta.4_ba36cda0091235ae5584a110a384179b - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-avatar-editor: 12.0.0_@babel+core@7.16.0 + react-hook-form: 7.18.1 + react-router: 6.0.0-beta.4_history@5.1.0 + react-router-dom: 6.0.0-beta.4_history@5.1.0 + react-use: 17.3.1 unstated-next: 1.1.0 urlcat: 2.0.4 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 uuid: 8.3.2 wallet.ts: 1.0.1 web3-utils: 1.5.3 zod: 3.11.6 devDependencies: '@babel/core': 7.16.0 - '@storybook/addon-actions': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-essentials': 6.4.0-alpha.38_8e5af5eeaf2e409dfbc851f77920bcf3 - '@storybook/addon-links': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/manager-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/react': 6.3.12_158e762f35d25e0f30388420e4124ec3 + '@storybook/addon-actions': 6.4.0-alpha.38 + '@storybook/addon-essentials': 6.4.0-alpha.38_5d77dcfb09d3227c5d32f6df65fbc534 + '@storybook/addon-links': 6.4.0-alpha.38 + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/manager-webpack5': 6.4.0-alpha.38 + '@storybook/react': 6.3.12_8a69853daa796dbcd7221fb09bd38bec babel-loader: 8.2.3_27ba53a5d4d1393445550229adea0ad0 buffer: 6.0.3 stream-browserify: 3.0.0 @@ -386,7 +386,7 @@ importers: '@balancer-labs/sor': 1.0.0 '@dimensiondev/common-protocols': 1.6.0-20210723072221-8f46a92 '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0_webextension-polyfill@0.8.0 - '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_9a9fcfd9691ee39f83ac00f4a3221da4 + '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7 '@dimensiondev/mask-wallet-core': 0.1.0-20211013082857-eb62e5f_protobufjs@6.11.2 '@dimensiondev/metamask-extension-provider': 3.0.6-20210519045409-1835d4d '@dimensiondev/snapshot.js': 0.2.0 @@ -470,17 +470,17 @@ importers: promievent: 0.1.5 protobufjs: 6.11.2 pvtsutils: 1.1.7 - react-draggable: 4.4.4_9a9fcfd9691ee39f83ac00f4a3221da4 - react-feather: 2.0.9_c9c210d65bdac3c3f586a38a4275dd8c - react-highlight-words: 0.17.0_c9c210d65bdac3c3f586a38a4275dd8c - react-hook-form: 7.18.1_c9c210d65bdac3c3f586a38a4275dd8c - react-router-dom: 5.3.0_c9c210d65bdac3c3f586a38a4275dd8c - react-transition-group: 4.4.2_9a9fcfd9691ee39f83ac00f4a3221da4 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 - react-virtualized-auto-sizer: 1.0.6_9a9fcfd9691ee39f83ac00f4a3221da4 - react-window: 1.8.6_9a9fcfd9691ee39f83ac00f4a3221da4 + react-draggable: 4.4.4 + react-feather: 2.0.9 + react-highlight-words: 0.17.0 + react-hook-form: 7.18.1 + react-router-dom: 5.3.0 + react-transition-group: 4.4.2 + react-use: 17.3.1 + react-virtualized-auto-sizer: 1.0.6 + react-window: 1.8.6 remarkable: 2.0.1 - rss3-next: 0.6.17_typescript@4.5.1-rc + rss3-next: 0.6.17 safari-14-idb-fix: 3.0.0 scrypt-js: 3.0.1 socket.io-client: 2.4.0 @@ -490,7 +490,7 @@ importers: ts-results: 3.3.0 unstated-next: 1.1.0 urlcat: 2.0.4 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 uuid: 8.3.2 wallet.ts: 1.0.1 web-ext-types: 3.2.1 @@ -504,13 +504,13 @@ importers: z-schema: 5.0.1 zod: 3.11.6 devDependencies: - '@dimensiondev/webextension-shim': 0.0.3-20210823035705-4257e12_typescript@4.5.1-rc + '@dimensiondev/webextension-shim': 0.0.3-20210823035705-4257e12 '@nice-labs/emit-file-webpack-plugin': 1.1.2_webpack@5.61.0 '@pmmmwh/react-refresh-webpack-plugin': 0.5.1_79e6f997decd3d88227983515e33d5a6 '@swc/core': 1.2.106 '@types/webpack-dev-server': 4.3.1_1786c5a86a664aa1b63bdcdf4cadede7 - '@typescript-eslint/eslint-plugin': 5.3.0_c0f26c2804ddda4720e68667d05234b5 - '@typescript-eslint/parser': 5.3.0_5ad87ec15ece8fc8da8d47a233a9a023 + '@typescript-eslint/eslint-plugin': 5.3.0_@typescript-eslint+parser@5.3.0 + '@typescript-eslint/parser': 5.3.0 copy-webpack-plugin: 9.0.1_webpack@5.61.0 html-webpack-plugin: 5.5.0_webpack@5.61.0 react-devtools-core: 4.21.0 @@ -559,7 +559,7 @@ importers: lodash-es: 4.17.21 ts-results: 3.3.0 unstated-next: 1.1.0 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 packages/plugins/Flow: specifiers: @@ -569,7 +569,9 @@ importers: '@masknet/shared-base': workspace:* '@masknet/theme': workspace:* '@masknet/web3-shared-flow': workspace:* + '@onflow/fcl': ^0.0.77 bignumber.js: ^9.0.1 + lodash-es: ^4.17.21 react-use: ^17.3.1 dependencies: '@masknet/icons': link:../../icons @@ -578,8 +580,10 @@ importers: '@masknet/shared-base': link:../../shared-base '@masknet/theme': link:../../theme '@masknet/web3-shared-flow': link:../../web3-shared/flow + '@onflow/fcl': 0.0.77 bignumber.js: 9.0.1 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + lodash-es: 4.17.21 + react-use: 17.3.1 packages/plugins/Wallet: specifiers: @@ -596,7 +600,7 @@ importers: '@masknet/theme': link:../../theme '@masknet/web3-shared-evm': link:../../web3-shared/evm bignumber.js: 9.0.1 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-use: 17.3.1 web3-core-helpers: 1.5.2 packages/plugins/example: @@ -657,7 +661,7 @@ importers: dependencies: '@types/rimraf': 3.0.2 chalk: 4.1.2 - gulp-zip: 5.1.0_gulp@4.0.2 + gulp-zip: 5.1.0 lodash: 4.17.21 proper-lockfile: 4.1.2 rimraf: 3.0.2 @@ -667,7 +671,7 @@ importers: '@types/inquirer': 7.3.3 '@types/lodash': 4.14.176 '@types/proper-lockfile': 4.1.2 - ts-node: 10.4.0_typescript@4.5.1-rc + ts-node: 10.4.0 packages/shared: specifiers: @@ -688,7 +692,7 @@ importers: uuid: ^8.3.2 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 - '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_9a9fcfd9691ee39f83ac00f4a3221da4 + '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7 '@masknet/icons': link:../icons '@masknet/shared-base': link:../shared-base '@masknet/theme': link:../theme @@ -698,9 +702,9 @@ importers: classnames: 2.3.1 lodash-es: 4.17.21 qrcode: 1.4.4 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-use: 17.3.1 ts-results: 3.3.0 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 uuid: 8.3.2 packages/shared-base: @@ -742,8 +746,8 @@ importers: '@storybook/addons': ^6.3.12 '@storybook/react': ^6.3.12 devDependencies: - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/react': 6.3.12_7c21731b976151a2ab0cda54216e1b22 + '@storybook/addons': 6.3.12 + '@storybook/react': 6.3.12 packages/theme: specifiers: @@ -777,20 +781,20 @@ importers: classnames: 2.3.1 fuse.js: 6.4.6 lodash-es: 4.17.21 - notistack: 2.0.3_4fde53ffa339abe904971fb02833fc6f - react-window: 1.8.6_9a9fcfd9691ee39f83ac00f4a3221da4 + notistack: 2.0.3 + react-window: 1.8.6 tinycolor2: 1.4.2 - tss-react: 2.0.1_@emotion+react@11.5.0 + tss-react: 2.0.1 unstated-next: 1.1.0 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 devDependencies: '@babel/core': 7.16.0 - '@storybook/addon-actions': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-essentials': 6.4.0-alpha.38_8e5af5eeaf2e409dfbc851f77920bcf3 - '@storybook/addon-links': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/manager-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/react': 6.3.12_158e762f35d25e0f30388420e4124ec3 + '@storybook/addon-actions': 6.4.0-alpha.38 + '@storybook/addon-essentials': 6.4.0-alpha.38_5d77dcfb09d3227c5d32f6df65fbc534 + '@storybook/addon-links': 6.4.0-alpha.38 + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/manager-webpack5': 6.4.0-alpha.38 + '@storybook/react': 6.3.12_8a69853daa796dbcd7221fb09bd38bec babel-loader: 8.2.3_27ba53a5d4d1393445550229adea0ad0 webpack: 5.61.0 @@ -806,7 +810,7 @@ importers: web3-eth-contract: 1.5.2 dependencies: '@typechain/web3-v1': 3.0.0_typechain@5.1.2 - typechain: 5.1.2_typescript@4.5.1-rc + typechain: 5.1.2 devDependencies: bn.js: 4.12.0 promievent: 0.1.5 @@ -835,7 +839,7 @@ importers: web3: 1.5.2 web3-utils: 1.5.2 dependencies: - '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7_9a9fcfd9691ee39f83ac00f4a3221da4 + '@dimensiondev/kit': 0.0.0-20210913111737-84c17d7 '@ensdomains/address-encoder': 0.2.6 '@masknet/web3-constants': link:../../web3-constants '@masknet/web3-contracts': link:../../web3-contracts @@ -844,10 +848,10 @@ importers: ethereum-blockies: 0.1.1 fuse.js: 6.4.6 lodash-es: 4.17.21 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-use: 17.3.1 unstated-next: 1.1.0 urlcat: 2.0.4 - use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + use-subscription: 1.5.1 wallet.ts: 1.0.1 web3: 1.5.2 web3-utils: 1.5.2 @@ -866,7 +870,7 @@ importers: '@masknet/web3-kit': link:../../web3-kit '@onflow/fcl': 0.0.77 '@onflow/types': 0.0.5 - react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-use: 17.3.1 packages/web3-shared/solana: specifiers: {} @@ -4765,7 +4769,7 @@ packages: webextension-polyfill: 0.8.0 dev: false - /@dimensiondev/kit/0.0.0-20210913111737-84c17d7_1f3bb381423595cffa34751168edda8e: + /@dimensiondev/kit/0.0.0-20210913111737-84c17d7: resolution: {integrity: sha512-a4gj6wHSzaonu+yvKaoOOYHWy74cEY1OPkIcmMMK2wJN++XzrZed0Trdth+F0bZCpj2XzWzolyYMHbmYiaX5ww==, tarball: download/@dimensiondev/kit/0.0.0-20210913111737-84c17d7/128b9a70ddf0e296c03baa891a25148518d15de3c3c750c2c58e507c31d4a0ad} peerDependencies: react: ^17 || ^18 @@ -4773,14 +4777,12 @@ packages: dependencies: bignumber.js: 9.0.1 lodash-es: 4.17.21 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-router: 6.0.0-beta.4_63e1619e79ddca1f1ecc330403c2f112 - react-use: 15.3.8_9a9fcfd9691ee39f83ac00f4a3221da4 + react-use: 15.3.8 transitivePeerDependencies: - react-dom dev: false - /@dimensiondev/kit/0.0.0-20210913111737-84c17d7_9a9fcfd9691ee39f83ac00f4a3221da4: + /@dimensiondev/kit/0.0.0-20210913111737-84c17d7_react-router@6.0.0-beta.4: resolution: {integrity: sha512-a4gj6wHSzaonu+yvKaoOOYHWy74cEY1OPkIcmMMK2wJN++XzrZed0Trdth+F0bZCpj2XzWzolyYMHbmYiaX5ww==, tarball: download/@dimensiondev/kit/0.0.0-20210913111737-84c17d7/128b9a70ddf0e296c03baa891a25148518d15de3c3c750c2c58e507c31d4a0ad} peerDependencies: react: ^17 || ^18 @@ -4788,8 +4790,8 @@ packages: dependencies: bignumber.js: 9.0.1 lodash-es: 4.17.21 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-use: 15.3.8_9a9fcfd9691ee39f83ac00f4a3221da4 + react-router: 6.0.0-beta.4_history@5.1.0 + react-use: 15.3.8 transitivePeerDependencies: - react-dom dev: false @@ -4865,7 +4867,7 @@ packages: meow: 7.1.1 dev: false - /@dimensiondev/webextension-shim/0.0.3-20210823035705-4257e12_typescript@4.5.1-rc: + /@dimensiondev/webextension-shim/0.0.3-20210823035705-4257e12: resolution: {integrity: sha512-zkpb1xzfyhWu9c5FZc4HHa5aBrUVdQCNGfmnUzNk2kU6AaCtfVeB4i39LLaPVLCP5nKKAVnbWNe88fGYSmcryw==, tarball: download/@dimensiondev/webextension-shim/0.0.3-20210823035705-4257e12/f0cf9f4c48531ee9828e0a0d2842d70212dc0f371b409054026fc17fcd3eef93} hasBin: true peerDependencies: @@ -4874,7 +4876,6 @@ packages: async-call-rpc: 4.2.1 buffer: 6.0.3 systemjs: 6.3.2 - typescript: 4.5.1-rc web-ext-types: 3.2.1 dev: true @@ -4921,7 +4922,7 @@ packages: stylis: 4.0.10 dev: false - /@emotion/core/10.1.1_c9c210d65bdac3c3f586a38a4275dd8c: + /@emotion/core/10.1.1: resolution: {integrity: sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==} peerDependencies: react: '>=16.3.0' @@ -4932,7 +4933,6 @@ packages: '@emotion/serialize': 0.11.16 '@emotion/sheet': 0.9.4 '@emotion/utils': 0.11.3 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /@emotion/css/10.0.27: @@ -5031,30 +5031,28 @@ packages: resolution: {integrity: sha512-YoX5GyQ4db7LpbmXHMuc8kebtBGP6nZfRC5Z13OKJMixBEwdZrJ914D6yJv/P+ZH/YY3F5s89NYX2hlZAf3SRQ==} dev: false - /@emotion/styled-base/10.0.31_29362b9726706a0ae276da7ff9e2fe66: + /@emotion/styled-base/10.0.31_@emotion+core@10.1.1: resolution: {integrity: sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==} peerDependencies: '@emotion/core': ^10.0.28 react: '>=16.3.0' dependencies: '@babel/runtime': 7.16.0 - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c + '@emotion/core': 10.1.1 '@emotion/is-prop-valid': 0.8.8 '@emotion/serialize': 0.11.16 '@emotion/utils': 0.11.3 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true - /@emotion/styled/10.0.27_29362b9726706a0ae276da7ff9e2fe66: + /@emotion/styled/10.0.27_@emotion+core@10.1.1: resolution: {integrity: sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==} peerDependencies: '@emotion/core': ^10.0.27 react: '>=16.3.0' dependencies: - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c - '@emotion/styled-base': 10.0.31_29362b9726706a0ae276da7ff9e2fe66 + '@emotion/core': 10.1.1 + '@emotion/styled-base': 10.0.31_@emotion+core@10.1.1 babel-plugin-emotion: 10.2.2 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /@emotion/styled/11.3.0_d36cd8dbf8213640c43ee9dfdf74e3f6: @@ -5594,7 +5592,7 @@ packages: peerDependencies: react-hook-form: ^7.0.0 dependencies: - react-hook-form: 7.18.1_c9c210d65bdac3c3f586a38a4275dd8c + react-hook-form: 7.18.1 dev: false /@humanwhocodes/config-array/0.5.0: @@ -5903,11 +5901,11 @@ packages: yargs: 16.2.0 dev: true - /@mdx-js/loader/1.6.22_c9c210d65bdac3c3f586a38a4275dd8c: + /@mdx-js/loader/1.6.22: resolution: {integrity: sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==} dependencies: '@mdx-js/mdx': 1.6.22 - '@mdx-js/react': 1.6.22_c9c210d65bdac3c3f586a38a4275dd8c + '@mdx-js/react': 1.6.22 loader-utils: 2.0.0 transitivePeerDependencies: - react @@ -5940,12 +5938,10 @@ packages: - supports-color dev: true - /@mdx-js/react/1.6.22_c9c210d65bdac3c3f586a38a4275dd8c: + /@mdx-js/react/1.6.22: resolution: {integrity: sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==} peerDependencies: react: ^16.13.1 || ^17.0.0 - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /@mdx-js/util/1.6.22: @@ -6549,17 +6545,15 @@ packages: resolution: {integrity: sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=} dev: false - /@reach/router/1.3.4_9a9fcfd9691ee39f83ac00f4a3221da4: + /@reach/router/1.3.4: resolution: {integrity: sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==} peerDependencies: react: 15.x || 16.x || 16.4.0-alpha.0911da3 react-dom: 15.x || 16.x || 16.4.0-alpha.0911da3 dependencies: - create-react-context: 0.3.0_9970b490fb16582c87a82f17acf5759d + create-react-context: 0.3.0_prop-types@15.7.2 invariant: 2.2.4 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c react-lifecycles-compat: 3.0.4 dev: true @@ -6663,7 +6657,7 @@ packages: resolution: {integrity: sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==} dev: false - /@storybook/addon-actions/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-actions/6.4.0-alpha.38: resolution: {integrity: sha512-/JMpfBRQ4ivgi7PTHH7SsjF+73TtsDFFulFMZJbajhhOBPDPLuaFQs8/DO2zssh3xcHxl2LNECe980EiJ98hfw==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6674,21 +6668,19 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 fast-deep-equal: 3.1.3 global: 4.4.0 lodash: 4.17.21 polished: 4.1.3 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-inspector: 5.1.1_c9c210d65bdac3c3f586a38a4275dd8c + react-inspector: 5.1.1 regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -6697,7 +6689,7 @@ packages: - '@types/react' dev: true - /@storybook/addon-backgrounds/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-backgrounds/6.4.0-alpha.38: resolution: {integrity: sha512-RRwsWnkW3KUk/ut5/MBuViaLSlKiV+sRzD74b6vlcbErv3tjZoRzDLKGdzEtg6kRHYnk3hZdHHI1bbdT2AY4mQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6708,18 +6700,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 global: 4.4.0 memoizerific: 1.11.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -6727,7 +6717,7 @@ packages: - '@types/react' dev: true - /@storybook/addon-controls/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-controls/6.4.0-alpha.38: resolution: {integrity: sha512-i1/WYcmSfYtqJyhuk+4y5jXwmRUFzqX6tiFgL+MJ9PIzRkA1PzEEt/MXLyz2Wof7oR8vO5iWCSIrnPGQgrveFw==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6738,24 +6728,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 '@storybook/node-logger': 6.4.0-alpha.38 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 lodash: 4.17.21 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/addon-docs/6.4.0-alpha.38_d7c00e6277296ce1d353d6b76690363a: + /@storybook/addon-docs/6.4.0-alpha.38_aedba8c7bf368c6d8de7913090af382f: resolution: {integrity: sha512-gAyPNOwF78cg1fQtdiX8rm3JwyAe7qW+EgYpgU1aAdKNXXfW7R1sihA79dQ14gpDHeP8YvtWqGWdPVaM2ojuyQ==} peerDependencies: '@storybook/angular': 6.4.0-alpha.38 @@ -6808,26 +6796,26 @@ packages: '@babel/plugin-transform-react-jsx': 7.14.9_@babel+core@7.16.0 '@babel/preset-env': 7.15.6_@babel+core@7.16.0 '@jest/transform': 26.6.2 - '@mdx-js/loader': 1.6.22_c9c210d65bdac3c3f586a38a4275dd8c + '@mdx-js/loader': 1.6.22 '@mdx-js/mdx': 1.6.22 - '@mdx-js/react': 1.6.22_c9c210d65bdac3c3f586a38a4275dd8c - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/builder-webpack4': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/client-api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@mdx-js/react': 1.6.22 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 + '@storybook/builder-webpack4': 6.4.0-alpha.38 + '@storybook/client-api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/core': 6.4.0-alpha.38_ca7d62b51f2cc1cbc24d8ff7394f954c + '@storybook/components': 6.4.0-alpha.38 + '@storybook/core': 6.4.0-alpha.38_638473a2a5f3f3e4ba897a68f2f4ea90 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 '@storybook/csf-tools': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 '@storybook/postinstall': 6.4.0-alpha.38 - '@storybook/preview-web': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/react': 6.3.12_158e762f35d25e0f30388420e4124ec3 - '@storybook/source-loader': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/preview-web': 6.4.0-alpha.38 + '@storybook/react': 6.3.12_8a69853daa796dbcd7221fb09bd38bec + '@storybook/source-loader': 6.4.0-alpha.38 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 acorn: 7.4.1 acorn-jsx: 5.3.2_acorn@7.4.1 acorn-walk: 7.2.0 @@ -6844,9 +6832,7 @@ packages: p-limit: 3.1.0 prettier: 2.4.1 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-element-to-jsx-string: 14.3.2_9a9fcfd9691ee39f83ac00f4a3221da4 + react-element-to-jsx-string: 14.3.2 regenerator-runtime: 0.13.9 remark-external-links: 8.0.0 remark-slug: 6.1.0 @@ -6863,7 +6849,7 @@ packages: - webpack-command dev: true - /@storybook/addon-essentials/6.4.0-alpha.38_8e5af5eeaf2e409dfbc851f77920bcf3: + /@storybook/addon-essentials/6.4.0-alpha.38_5d77dcfb09d3227c5d32f6df65fbc534: resolution: {integrity: sha512-rdKQWubRzC8QuKF2fyj1jlX91NeVGl80FTSgL9O364saXHBuUKqY4PISuQkNVtNxR7LTn8MZM2Wq+oNMvNP/wg==} peerDependencies: '@babel/core': ^7.9.6 @@ -6889,21 +6875,19 @@ packages: optional: true dependencies: '@babel/core': 7.16.0 - '@storybook/addon-actions': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-backgrounds': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-controls': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-docs': 6.4.0-alpha.38_d7c00e6277296ce1d353d6b76690363a - '@storybook/addon-measure': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-outline': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-toolbars': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addon-viewport': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addon-actions': 6.4.0-alpha.38 + '@storybook/addon-backgrounds': 6.4.0-alpha.38 + '@storybook/addon-controls': 6.4.0-alpha.38 + '@storybook/addon-docs': 6.4.0-alpha.38_aedba8c7bf368c6d8de7913090af382f + '@storybook/addon-measure': 6.4.0-alpha.38 + '@storybook/addon-outline': 6.4.0-alpha.38 + '@storybook/addon-toolbars': 6.4.0-alpha.38 + '@storybook/addon-viewport': 6.4.0-alpha.38 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 babel-loader: 8.2.3_27ba53a5d4d1393445550229adea0ad0 core-js: 3.17.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 webpack: 5.61.0 @@ -6925,7 +6909,7 @@ packages: - webpack-command dev: true - /@storybook/addon-links/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/addon-links/6.4.0-alpha.38: resolution: {integrity: sha512-vWqXgwGHjbXnSB3oS2bLxRDe+SQfO1BruTdIDjmyTS1w0YOOMOlFMCv3DEeiWDGvo/tLGPU+ht0fjbVZ8vVFcQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6936,23 +6920,21 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.4.0-alpha.38 '@types/qs': 6.9.7 core-js: 3.17.3 global: 4.4.0 prop-types: 15.7.2 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-measure/6.4.0-alpha.38: resolution: {integrity: sha512-kB77H8GyaoSWbZ1NzKNP1/K+DpFPddsJZvQn+v0ufyZpapUm5elHbJvE6vq8LsFtas5tEu5p1YHnX9OWHRHSiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6963,21 +6945,19 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 core-js: 3.17.3 global: 4.4.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c transitivePeerDependencies: - '@types/react' dev: true - /@storybook/addon-outline/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-outline/6.4.0-alpha.38: resolution: {integrity: sha512-lX+fXvL/+/bwaNUFneG0jtbDbp4biUUpbALFsEL94YtEc3bAUOiGdO6CHZmHOcchP1780RSYJ2UEW4qJDsFGfQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -6988,23 +6968,21 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 core-js: 3.17.3 global: 4.4.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/addon-toolbars/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-toolbars/6.4.0-alpha.38: resolution: {integrity: sha512-7xyHrNrMcAlF7Su5YVa4fAMiUWO26u8e8Oe6jHn6zUKHmZYwq7wlO4NnInGt4P4ES1KtPIY7mwvPJISqjc97qA==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7015,19 +6993,17 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 + '@storybook/components': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/addon-viewport/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/addon-viewport/6.4.0-alpha.38: resolution: {integrity: sha512-agJnAOrS8W5AyBJcvnMLrTe+0QmUY96/K9orcxSN7FLrQc+feq+7bvtlf42FeDhYbU44J9Zu4ualZk0IrGigZg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7038,76 +7014,70 @@ packages: react-dom: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 global: 4.4.0 memoizerific: 1.11.3 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/addons/6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/addons/6.3.12: resolution: {integrity: sha512-UgoMyr7Qr0FS3ezt8u6hMEcHgyynQS9ucr5mAwZky3wpXRPFyUTmMto9r4BBUdqyUvTUj/LRKIcmLBfj+/l0Fg==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/api': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/api': 6.3.12 '@storybook/channels': 6.3.12 '@storybook/client-logger': 6.3.12 '@storybook/core-events': 6.3.12 - '@storybook/router': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.3.12 + '@storybook/theming': 6.3.12 core-js: 3.19.1 global: 4.4.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 dev: true - /@storybook/addons/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/addons/6.4.0-alpha.38: resolution: {integrity: sha512-VMzPSf53OVSepr1L820K2p5RCA6DgayCgR5I9AvRiIN1felZ4w/ziggIQ86bsK6KyEKrp6e06gsSQeHEEsQgcA==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/api': 6.4.0-alpha.38 '@storybook/channels': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 core-js: 3.17.3 global: 4.4.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 dev: true - /@storybook/api/6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/api/6.3.12: resolution: {integrity: sha512-LScRXUeCWEW/OP+jiooNMQICVdusv7azTmULxtm72fhkXFRiQs2CdRNTiqNg46JLLC9z95f1W+pGK66X6HiiQA==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@reach/router': 1.3.4_9a9fcfd9691ee39f83ac00f4a3221da4 + '@reach/router': 1.3.4 '@storybook/channels': 6.3.12 '@storybook/client-logger': 6.3.12 '@storybook/core-events': 6.3.12 '@storybook/csf': 0.0.1 - '@storybook/router': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.3.12 '@storybook/semver': 7.3.2 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.3.12 '@types/reach__router': 1.3.9 core-js: 3.19.1 fast-deep-equal: 3.1.3 @@ -7115,8 +7085,6 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 store2: 2.12.0 telejson: 5.3.3 @@ -7124,20 +7092,20 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/api/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/api/6.4.0-alpha.38: resolution: {integrity: sha512-lNlBDlEhBORYCMbS1iMoUN3KbkWOVWTOX2FGDlSlBZ6le1abWGOdh+tjjOjSm5fcbNpGhLS4jn/bM6d/HnhW3A==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@reach/router': 1.3.4_9a9fcfd9691ee39f83ac00f4a3221da4 + '@reach/router': 1.3.4 '@storybook/channels': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.4.0-alpha.38 '@storybook/semver': 7.3.2 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 '@types/reach__router': 1.3.9 core-js: 3.17.3 fast-deep-equal: 3.1.3 @@ -7145,8 +7113,6 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 store2: 2.12.0 telejson: 5.3.3 @@ -7154,7 +7120,7 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/builder-webpack4/6.3.12_7c21731b976151a2ab0cda54216e1b22: + /@storybook/builder-webpack4/6.3.12: resolution: {integrity: sha512-Dlm5Fc1svqpFDnVPZdAaEBiM/IDZHMV3RfEGbUTY/ZC0q8b/Ug1czzp/w0aTIjOFRuBDcG6IcplikaqHL8CJLg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7185,20 +7151,20 @@ packages: '@babel/preset-env': 7.16.0_@babel+core@7.16.0 '@babel/preset-react': 7.16.0_@babel+core@7.16.0 '@babel/preset-typescript': 7.16.0_@babel+core@7.16.0 - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.3.12 + '@storybook/api': 6.3.12 '@storybook/channel-postmessage': 6.3.12 '@storybook/channels': 6.3.12 - '@storybook/client-api': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.3.12 '@storybook/client-logger': 6.3.12 - '@storybook/components': 6.3.12_14da01773538ca517609d7bab0ada649 - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 + '@storybook/components': 6.3.12 + '@storybook/core-common': 6.3.12 '@storybook/core-events': 6.3.12 '@storybook/node-logger': 6.3.12 - '@storybook/router': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.3.12 '@storybook/semver': 7.3.2 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.3.12_14da01773538ca517609d7bab0ada649 + '@storybook/theming': 6.3.12 + '@storybook/ui': 6.3.12 '@types/node': 16.11.6 '@types/webpack': 4.41.31 autoprefixer: 9.8.8 @@ -7217,19 +7183,16 @@ packages: glob-promise: 3.4.0_glob@7.2.0 global: 4.4.0 html-webpack-plugin: 4.5.2_webpack@4.46.0 - pnp-webpack-plugin: 1.6.4_typescript@4.5.1-rc + pnp-webpack-plugin: 1.6.4 postcss: 7.0.39 postcss-flexbugs-fixes: 4.2.1 postcss-loader: 4.3.0_postcss@7.0.39+webpack@4.46.0 raw-loader: 4.0.2_webpack@4.46.0 - react: 18.0.0-alpha-00ced1e2b-20211102 react-dev-utils: 11.0.4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c stable: 0.1.8 style-loader: 1.3.0_webpack@4.46.0 terser-webpack-plugin: 4.2.3_webpack@4.46.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc url-loader: 4.1.1_file-loader@6.2.0+webpack@4.46.0 util-deprecate: 1.0.2 webpack: 4.46.0 @@ -7246,7 +7209,7 @@ packages: - webpack-command dev: true - /@storybook/builder-webpack4/6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735: + /@storybook/builder-webpack4/6.4.0-alpha.38: resolution: {integrity: sha512-Qm6NPUKyGryRnEmn02YbDbqGTsqOF2cIDvfvR3pn/TxaxECt/rHF/ZKPtCFZYA7FhnMspVPbn/ebT//GXKQXHg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7277,22 +7240,22 @@ packages: '@babel/preset-env': 7.15.6_@babel+core@7.16.0 '@babel/preset-react': 7.16.0_@babel+core@7.16.0 '@babel/preset-typescript': 7.16.0_@babel+core@7.16.0 - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 '@storybook/channels': 6.4.0-alpha.38 - '@storybook/client-api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/core-common': 6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb + '@storybook/components': 6.4.0-alpha.38 + '@storybook/core-common': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 - '@storybook/preview-web': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/preview-web': 6.4.0-alpha.38 + '@storybook/router': 6.4.0-alpha.38 '@storybook/semver': 7.3.2 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 + '@storybook/ui': 6.4.0-alpha.38 '@types/node': 16.11.6 '@types/webpack': 4.41.31 autoprefixer: 9.8.6 @@ -7310,19 +7273,16 @@ packages: glob-promise: 3.4.0_glob@7.2.0 global: 4.4.0 html-webpack-plugin: 4.5.2_webpack@4.46.0 - pnp-webpack-plugin: 1.6.4_typescript@4.5.1-rc + pnp-webpack-plugin: 1.6.4 postcss: 7.0.36 postcss-flexbugs-fixes: 4.2.1 postcss-loader: 4.3.0_postcss@7.0.36+webpack@4.46.0 raw-loader: 4.0.2_webpack@4.46.0 - react: 18.0.0-alpha-00ced1e2b-20211102 react-dev-utils: 11.0.4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c stable: 0.1.8 style-loader: 1.3.0_webpack@4.46.0 terser-webpack-plugin: 4.2.3_webpack@4.46.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc url-loader: 4.1.1_file-loader@6.2.0+webpack@4.46.0 util-deprecate: 1.0.2 webpack: 4.46.0 @@ -7337,7 +7297,7 @@ packages: - webpack-command dev: true - /@storybook/builder-webpack5/6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735: + /@storybook/builder-webpack5/6.4.0-alpha.38: resolution: {integrity: sha512-8xd5Xi1ebWPcM1pw0/Xwf5XcPjXdsx+DvL2ixQtOr+AnOqHtbOaTRbKJXeiWiVMW5lyqxxjWdhNn47qB2JZUSA==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7367,21 +7327,21 @@ packages: '@babel/preset-env': 7.15.6_@babel+core@7.16.0 '@babel/preset-react': 7.14.5_@babel+core@7.16.0 '@babel/preset-typescript': 7.15.0_@babel+core@7.16.0 - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 '@storybook/channels': 6.4.0-alpha.38 - '@storybook/client-api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 - '@storybook/core-common': 6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb + '@storybook/components': 6.4.0-alpha.38 + '@storybook/core-common': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 - '@storybook/preview-web': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/preview-web': 6.4.0-alpha.38 + '@storybook/router': 6.4.0-alpha.38 '@storybook/semver': 7.3.2 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/theming': 6.4.0-alpha.38 '@types/node': 16.11.6 babel-loader: 8.2.3_27ba53a5d4d1393445550229adea0ad0 babel-plugin-macros: 3.1.0 @@ -7394,14 +7354,11 @@ packages: glob: 7.1.7 glob-promise: 3.4.0_glob@7.1.7 html-webpack-plugin: 5.3.2_webpack@5.61.0 - react: 18.0.0-alpha-00ced1e2b-20211102 react-dev-utils: 11.0.4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c stable: 0.1.8 style-loader: 2.0.0_webpack@5.61.0 terser-webpack-plugin: 5.2.4_webpack@5.61.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 5.61.0 webpack-dev-middleware: 4.3.0_webpack@5.61.0 @@ -7457,13 +7414,13 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/client-api/6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/client-api/6.3.12: resolution: {integrity: sha512-xnW+lKKK2T774z+rOr9Wopt1aYTStfb86PSs9p3Fpnc2Btcftln+C3NtiHZl8Ccqft8Mz/chLGgewRui6tNI8g==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.3.12 '@storybook/channel-postmessage': 6.3.12 '@storybook/channels': 6.3.12 '@storybook/client-logger': 6.3.12 @@ -7476,8 +7433,6 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 stable: 0.1.8 store2: 2.12.0 @@ -7485,19 +7440,19 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/client-api/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/client-api/6.4.0-alpha.38: resolution: {integrity: sha512-exW14ktv4WmvkHmvU9GbIY8NI4cgwIu6J1ICXcb3JoElp37zXBOI1krna6suPHk/cKza1N5S099TGKOEVFVSHw==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 '@storybook/channels': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/store': 6.4.0-alpha.38 '@types/qs': 6.9.7 '@types/webpack-env': 1.16.3 core-js: 3.17.3 @@ -7506,8 +7461,6 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 stable: 0.1.8 store2: 2.12.0 @@ -7529,7 +7482,7 @@ packages: global: 4.4.0 dev: true - /@storybook/components/6.3.12_14da01773538ca517609d7bab0ada649: + /@storybook/components/6.3.12: resolution: {integrity: sha512-kdQt8toUjynYAxDLrJzuG7YSNL6as1wJoyzNUaCfG06YPhvIAlKo7le9tS2mThVFN5e9nbKrW3N1V1sp6ypZXQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7538,7 +7491,7 @@ packages: '@popperjs/core': 2.10.2 '@storybook/client-logger': 6.3.12 '@storybook/csf': 0.0.1 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.3.12 '@types/color-convert': 2.0.0 '@types/overlayscrollbars': 1.12.1 '@types/react-syntax-highlighter': 11.0.5 @@ -7547,17 +7500,15 @@ packages: fast-deep-equal: 3.1.3 global: 4.4.0 lodash: 4.17.21 - markdown-to-jsx: 7.1.3_c9c210d65bdac3c3f586a38a4275dd8c + markdown-to-jsx: 7.1.3 memoizerific: 1.11.3 overlayscrollbars: 1.13.1 polished: 4.1.3 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-colorful: 5.5.0_9a9fcfd9691ee39f83ac00f4a3221da4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-popper-tooltip: 3.1.1_9a9fcfd9691ee39f83ac00f4a3221da4 - react-syntax-highlighter: 13.5.3_c9c210d65bdac3c3f586a38a4275dd8c - react-textarea-autosize: 8.3.3_6b5df8fda4c0b6d9d2f517da6b1996a3 + react-colorful: 5.5.0 + react-popper-tooltip: 3.1.1 + react-syntax-highlighter: 13.5.3 + react-textarea-autosize: 8.3.3 regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -7565,7 +7516,7 @@ packages: - '@types/react' dev: true - /@storybook/components/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/components/6.4.0-alpha.38: resolution: {integrity: sha512-Ks99CNZgLzFiRxpOiQrTI60MUEJbCKfKNHFuQCyoaUcuDYPPUOLa1DfX7w+i2/qOUup4aUMtPi1zM1gyRlui2w==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7574,7 +7525,7 @@ packages: '@popperjs/core': 2.10.1 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 '@types/color-convert': 2.0.0 '@types/overlayscrollbars': 1.12.1 '@types/react-syntax-highlighter': 11.0.5 @@ -7583,17 +7534,15 @@ packages: fast-deep-equal: 3.1.3 global: 4.4.0 lodash: 4.17.21 - markdown-to-jsx: 7.1.3_c9c210d65bdac3c3f586a38a4275dd8c + markdown-to-jsx: 7.1.3 memoizerific: 1.11.3 overlayscrollbars: 1.13.1 polished: 4.1.3 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-colorful: 5.4.0_9a9fcfd9691ee39f83ac00f4a3221da4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-popper-tooltip: 3.1.1_9a9fcfd9691ee39f83ac00f4a3221da4 - react-syntax-highlighter: 13.5.3_c9c210d65bdac3c3f586a38a4275dd8c - react-textarea-autosize: 8.3.3_6b5df8fda4c0b6d9d2f517da6b1996a3 + react-colorful: 5.4.0 + react-popper-tooltip: 3.1.1 + react-syntax-highlighter: 13.5.3 + react-textarea-autosize: 8.3.3 regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -7601,7 +7550,7 @@ packages: - '@types/react' dev: true - /@storybook/core-client/6.3.12_d3b2e7054986d6455c553801d231a734: + /@storybook/core-client/6.3.12_webpack@4.46.0: resolution: {integrity: sha512-8Smd9BgZHJpAdevLKQYinwtjSyCZAuBMoetP4P5hnn53mWl0NFbrHFaAdT+yNchDLZQUbf7Y18VmIqEH+RCR5w==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7612,24 +7561,21 @@ packages: typescript: optional: true dependencies: - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.3.12 '@storybook/channel-postmessage': 6.3.12 - '@storybook/client-api': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.3.12 '@storybook/client-logger': 6.3.12 '@storybook/core-events': 6.3.12 '@storybook/csf': 0.0.1 - '@storybook/ui': 6.3.12_14da01773538ca517609d7bab0ada649 + '@storybook/ui': 6.3.12 airbnb-js-shims: 2.2.1 ansi-to-html: 0.6.15 core-js: 3.19.1 global: 4.4.0 lodash: 4.17.21 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 - typescript: 4.5.1-rc unfetch: 4.2.0 util-deprecate: 1.0.2 webpack: 4.46.0 @@ -7637,7 +7583,7 @@ packages: - '@types/react' dev: true - /@storybook/core-client/6.4.0-alpha.38_68e084f59326e467d6f76b3371209ac0: + /@storybook/core-client/6.4.0-alpha.38_webpack@4.46.0: resolution: {integrity: sha512-zdWvJZEUvz36b7yZWs0XYdR2aLCtc6usjORm2MA92uEFJGMUhKyn6XNEOhE4R/aSZykbK35z/wDMwHowxUNVmg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7648,35 +7594,32 @@ packages: typescript: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 - '@storybook/client-api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/preview-web': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/preview-web': 6.4.0-alpha.38 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/ui': 6.4.0-alpha.38 airbnb-js-shims: 2.2.1 ansi-to-html: 0.6.15 core-js: 3.17.3 global: 4.4.0 lodash: 4.17.21 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 slash: 3.0.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 5.61.0 + webpack: 4.46.0 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/core-client/6.4.0-alpha.38_d3b2e7054986d6455c553801d231a734: + /@storybook/core-client/6.4.0-alpha.38_webpack@5.61.0: resolution: {integrity: sha512-zdWvJZEUvz36b7yZWs0XYdR2aLCtc6usjORm2MA92uEFJGMUhKyn6XNEOhE4R/aSZykbK35z/wDMwHowxUNVmg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7687,35 +7630,32 @@ packages: typescript: optional: true dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 - '@storybook/client-api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/client-api': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/preview-web': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/preview-web': 6.4.0-alpha.38 + '@storybook/store': 6.4.0-alpha.38 + '@storybook/ui': 6.4.0-alpha.38 airbnb-js-shims: 2.2.1 ansi-to-html: 0.6.15 core-js: 3.17.3 global: 4.4.0 lodash: 4.17.21 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 slash: 3.0.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 4.46.0 + webpack: 5.61.0 transitivePeerDependencies: - '@types/react' dev: true - /@storybook/core-common/6.3.12_97850682f79266241e42764eb32e5172: + /@storybook/core-common/6.3.12: resolution: {integrity: sha512-xlHs2QXELq/moB4MuXjYOczaxU64BIseHsnFBLyboJYN6Yso3qihW5RB7cuJlGohkjb4JwY74dvfT4Ww66rkBA==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7760,7 +7700,7 @@ packages: express: 4.17.1 file-system-cache: 1.0.5 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.4.0_ea712fb27c7b0f932a8b3dd814d4d586 + fork-ts-checker-webpack-plugin: 6.4.0_webpack@4.46.0 glob: 7.2.0 glob-base: 0.3.0 interpret: 2.2.0 @@ -7769,11 +7709,8 @@ packages: micromatch: 4.0.4 pkg-dir: 5.0.0 pretty-hrtime: 1.0.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c resolve-from: 5.0.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -7784,7 +7721,7 @@ packages: - webpack-command dev: true - /@storybook/core-common/6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb: + /@storybook/core-common/6.4.0-alpha.38: resolution: {integrity: sha512-Nt7AaRAIFuLJ5VGHJQgYYZyv9sbXRHhKRFCcYK5tZvQLXOKCKympMkzX/7whdOi7xr59apqj24LjzwE0GZLYVg==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -7838,11 +7775,8 @@ packages: micromatch: 4.0.4 pkg-dir: 5.0.0 pretty-hrtime: 1.0.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c resolve-from: 5.0.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -7863,7 +7797,7 @@ packages: core-js: 3.17.3 dev: true - /@storybook/core-server/6.3.12_158e762f35d25e0f30388420e4124ec3: + /@storybook/core-server/6.3.12: resolution: {integrity: sha512-T/Mdyi1FVkUycdyOnhXvoo3d9nYXLQFkmaJkltxBFLzAePAJUSgAsPL9odNC3+p8Nr2/UDsDzvu/Ow0IF0mzLQ==} peerDependencies: '@storybook/builder-webpack5': 6.3.12 @@ -7880,13 +7814,11 @@ packages: optional: true dependencies: '@discoveryjs/json-ext': 0.5.5 - '@storybook/builder-webpack4': 6.3.12_7c21731b976151a2ab0cda54216e1b22 - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/core-client': 6.3.12_d3b2e7054986d6455c553801d231a734 - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 - '@storybook/csf-tools': 6.3.12_@babel+core@7.16.0 - '@storybook/manager-webpack4': 6.3.12_7c21731b976151a2ab0cda54216e1b22 - '@storybook/manager-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 + '@storybook/builder-webpack4': 6.3.12 + '@storybook/core-client': 6.3.12_webpack@4.46.0 + '@storybook/core-common': 6.3.12 + '@storybook/csf-tools': 6.3.12 + '@storybook/manager-webpack4': 6.3.12 '@storybook/node-logger': 6.3.12 '@storybook/semver': 7.3.2 '@types/node': 16.11.6 @@ -7910,12 +7842,9 @@ packages: node-fetch: 2.6.6 pretty-hrtime: 1.0.3 prompts: 2.4.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 serve-favicon: 2.5.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -7928,7 +7857,7 @@ packages: - webpack-command dev: true - /@storybook/core-server/6.3.12_7c21731b976151a2ab0cda54216e1b22: + /@storybook/core-server/6.3.12_8a69853daa796dbcd7221fb09bd38bec: resolution: {integrity: sha512-T/Mdyi1FVkUycdyOnhXvoo3d9nYXLQFkmaJkltxBFLzAePAJUSgAsPL9odNC3+p8Nr2/UDsDzvu/Ow0IF0mzLQ==} peerDependencies: '@storybook/builder-webpack5': 6.3.12 @@ -7945,11 +7874,13 @@ packages: optional: true dependencies: '@discoveryjs/json-ext': 0.5.5 - '@storybook/builder-webpack4': 6.3.12_7c21731b976151a2ab0cda54216e1b22 - '@storybook/core-client': 6.3.12_d3b2e7054986d6455c553801d231a734 - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 - '@storybook/csf-tools': 6.3.12 - '@storybook/manager-webpack4': 6.3.12_7c21731b976151a2ab0cda54216e1b22 + '@storybook/builder-webpack4': 6.3.12 + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/core-client': 6.3.12_webpack@4.46.0 + '@storybook/core-common': 6.3.12 + '@storybook/csf-tools': 6.3.12_@babel+core@7.16.0 + '@storybook/manager-webpack4': 6.3.12 + '@storybook/manager-webpack5': 6.4.0-alpha.38 '@storybook/node-logger': 6.3.12 '@storybook/semver': 7.3.2 '@types/node': 16.11.6 @@ -7973,12 +7904,9 @@ packages: node-fetch: 2.6.6 pretty-hrtime: 1.0.3 prompts: 2.4.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 serve-favicon: 2.5.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -7991,7 +7919,7 @@ packages: - webpack-command dev: true - /@storybook/core-server/6.4.0-alpha.38_a96bb89a57cebe9f3d860e3b44b7d00b: + /@storybook/core-server/6.4.0-alpha.38_f1078765cdd61864f5a8ccd729e9d22b: resolution: {integrity: sha512-2h0PlZljVC8mZUfVxTusPcQz7YahPbFpB0BxNB8UIouFiV/HG9oZjVsKCbEAQQ7JZBncpkexKpiho7kpQblmjQ==} peerDependencies: '@storybook/builder-webpack5': 6.4.0-alpha.38 @@ -8008,13 +7936,13 @@ packages: optional: true dependencies: '@discoveryjs/json-ext': 0.5.5 - '@storybook/builder-webpack4': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/core-client': 6.4.0-alpha.38_d3b2e7054986d6455c553801d231a734 - '@storybook/core-common': 6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb + '@storybook/builder-webpack4': 6.4.0-alpha.38 + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/core-client': 6.4.0-alpha.38_webpack@4.46.0 + '@storybook/core-common': 6.4.0-alpha.38 '@storybook/csf-tools': 6.4.0-alpha.38 - '@storybook/manager-webpack4': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/manager-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 + '@storybook/manager-webpack4': 6.4.0-alpha.38 + '@storybook/manager-webpack5': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 '@storybook/semver': 7.3.2 '@types/node': 16.11.6 @@ -8038,12 +7966,9 @@ packages: node-fetch: 2.6.6 pretty-hrtime: 1.0.3 prompts: 2.4.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 serve-favicon: 2.5.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -8053,7 +7978,7 @@ packages: - webpack-command dev: true - /@storybook/core/6.3.12_892f44ca87711d14370428e777de45ce: + /@storybook/core/6.3.12_485bc28f394fa22a848285efd9af0be0: resolution: {integrity: sha512-FJm2ns8wk85hXWKslLWiUWRWwS9KWRq7jlkN6M9p57ghFseSGr4W71Orcoab4P3M7jI97l5yqBfppbscinE74g==} peerDependencies: '@storybook/builder-webpack5': 6.3.12 @@ -8066,11 +7991,9 @@ packages: typescript: optional: true dependencies: - '@storybook/core-client': 6.3.12_d3b2e7054986d6455c553801d231a734 - '@storybook/core-server': 6.3.12_7c21731b976151a2ab0cda54216e1b22 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - typescript: 4.5.1-rc + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/core-client': 6.3.12_webpack@4.46.0 + '@storybook/core-server': 6.3.12_8a69853daa796dbcd7221fb09bd38bec transitivePeerDependencies: - '@babel/core' - '@storybook/manager-webpack5' @@ -8083,7 +8006,7 @@ packages: - webpack-command dev: true - /@storybook/core/6.3.12_ca90ea5d8a9c7361c126c5d64363356d: + /@storybook/core/6.3.12_webpack@4.46.0: resolution: {integrity: sha512-FJm2ns8wk85hXWKslLWiUWRWwS9KWRq7jlkN6M9p57ghFseSGr4W71Orcoab4P3M7jI97l5yqBfppbscinE74g==} peerDependencies: '@storybook/builder-webpack5': 6.3.12 @@ -8096,12 +8019,8 @@ packages: typescript: optional: true dependencies: - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/core-client': 6.3.12_d3b2e7054986d6455c553801d231a734 - '@storybook/core-server': 6.3.12_158e762f35d25e0f30388420e4124ec3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - typescript: 4.5.1-rc + '@storybook/core-client': 6.3.12_webpack@4.46.0 + '@storybook/core-server': 6.3.12 transitivePeerDependencies: - '@babel/core' - '@storybook/manager-webpack5' @@ -8114,7 +8033,7 @@ packages: - webpack-command dev: true - /@storybook/core/6.4.0-alpha.38_ca7d62b51f2cc1cbc24d8ff7394f954c: + /@storybook/core/6.4.0-alpha.38_638473a2a5f3f3e4ba897a68f2f4ea90: resolution: {integrity: sha512-FlIeRjtL7K9aj+NELeEncX6n1zP9vKihc+Wqd2gH15EV59FwH+cs7SOEq6UJXl+Y1G0u9QEG5mByfyVi6tp9Jw==} peerDependencies: '@storybook/builder-webpack5': 6.4.0-alpha.38 @@ -8128,12 +8047,9 @@ packages: typescript: optional: true dependencies: - '@storybook/builder-webpack5': 6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735 - '@storybook/core-client': 6.4.0-alpha.38_68e084f59326e467d6f76b3371209ac0 - '@storybook/core-server': 6.4.0-alpha.38_a96bb89a57cebe9f3d860e3b44b7d00b - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - typescript: 4.5.1-rc + '@storybook/builder-webpack5': 6.4.0-alpha.38 + '@storybook/core-client': 6.4.0-alpha.38_webpack@5.61.0 + '@storybook/core-server': 6.4.0-alpha.38_f1078765cdd61864f5a8ccd729e9d22b webpack: 5.61.0 transitivePeerDependencies: - '@storybook/manager-webpack5' @@ -8222,7 +8138,7 @@ packages: lodash: 4.17.21 dev: true - /@storybook/manager-webpack4/6.3.12_7c21731b976151a2ab0cda54216e1b22: + /@storybook/manager-webpack4/6.3.12: resolution: {integrity: sha512-OkPYNrHXg2yZfKmEfTokP6iKx4OLTr0gdI5yehi/bLEuQCSHeruxBc70Dxm1GBk1Mrf821wD9WqMXNDjY5Qtug==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -8235,12 +8151,12 @@ packages: '@babel/core': 7.16.0 '@babel/plugin-transform-template-literals': 7.16.0_@babel+core@7.16.0 '@babel/preset-react': 7.16.0_@babel+core@7.16.0 - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/core-client': 6.3.12_d3b2e7054986d6455c553801d231a734 - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 + '@storybook/addons': 6.3.12 + '@storybook/core-client': 6.3.12_webpack@4.46.0 + '@storybook/core-common': 6.3.12 '@storybook/node-logger': 6.3.12 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.3.12_14da01773538ca517609d7bab0ada649 + '@storybook/theming': 6.3.12 + '@storybook/ui': 6.3.12 '@types/node': 16.11.6 '@types/webpack': 4.41.31 babel-loader: 8.2.3_1bd60a6cd0f7024f034efd75ae733a3f @@ -8256,9 +8172,7 @@ packages: fs-extra: 9.1.0 html-webpack-plugin: 4.5.2_webpack@4.46.0 node-fetch: 2.6.6 - pnp-webpack-plugin: 1.6.4_typescript@4.5.1-rc - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c + pnp-webpack-plugin: 1.6.4 read-pkg-up: 7.0.1 regenerator-runtime: 0.13.9 resolve-from: 5.0.0 @@ -8266,7 +8180,6 @@ packages: telejson: 5.3.3 terser-webpack-plugin: 4.2.3_webpack@4.46.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc url-loader: 4.1.1_file-loader@6.2.0+webpack@4.46.0 util-deprecate: 1.0.2 webpack: 4.46.0 @@ -8281,7 +8194,7 @@ packages: - webpack-command dev: true - /@storybook/manager-webpack4/6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735: + /@storybook/manager-webpack4/6.4.0-alpha.38: resolution: {integrity: sha512-n/GBc1BlWofM3SM7AyxaIvGpF/v+12gX1QkphQ2Y23lXTT6LRUFn+493HcJ4zIGdLwdelaRX1fAkuuhl0HdG5w==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -8294,12 +8207,12 @@ packages: '@babel/core': 7.16.0 '@babel/plugin-transform-template-literals': 7.16.0_@babel+core@7.16.0 '@babel/preset-react': 7.16.0_@babel+core@7.16.0 - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/core-client': 6.4.0-alpha.38_d3b2e7054986d6455c553801d231a734 - '@storybook/core-common': 6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/core-client': 6.4.0-alpha.38_webpack@4.46.0 + '@storybook/core-common': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/theming': 6.4.0-alpha.38 + '@storybook/ui': 6.4.0-alpha.38 '@types/node': 16.11.6 '@types/webpack': 4.41.31 babel-loader: 8.2.3_1bd60a6cd0f7024f034efd75ae733a3f @@ -8315,9 +8228,7 @@ packages: fs-extra: 9.1.0 html-webpack-plugin: 4.5.2_webpack@4.46.0 node-fetch: 2.6.6 - pnp-webpack-plugin: 1.6.4_typescript@4.5.1-rc - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c + pnp-webpack-plugin: 1.6.4 read-pkg-up: 7.0.1 regenerator-runtime: 0.13.9 resolve-from: 5.0.0 @@ -8325,7 +8236,6 @@ packages: telejson: 5.3.3 terser-webpack-plugin: 4.2.3_webpack@4.46.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc url-loader: 4.1.1_file-loader@6.2.0+webpack@4.46.0 util-deprecate: 1.0.2 webpack: 4.46.0 @@ -8338,7 +8248,7 @@ packages: - webpack-command dev: true - /@storybook/manager-webpack5/6.4.0-alpha.38_c446173119bb7d1f20f1c8548774b735: + /@storybook/manager-webpack5/6.4.0-alpha.38: resolution: {integrity: sha512-BIgcg3No2GFf/Rnqb++GBdDekXm6MxuD45Tg0N4e7wxpZkXExVQETdRNodgk9r3dwBdbadIlpYIR/mJOdG3UpA==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -8351,12 +8261,12 @@ packages: '@babel/core': 7.16.0 '@babel/plugin-transform-template-literals': 7.14.5_@babel+core@7.16.0 '@babel/preset-react': 7.14.5_@babel+core@7.16.0 - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/core-client': 6.4.0-alpha.38_68e084f59326e467d6f76b3371209ac0 - '@storybook/core-common': 6.4.0-alpha.38_22876905030d5ebe3dd566c1c0c609bb + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/core-client': 6.4.0-alpha.38_webpack@5.61.0 + '@storybook/core-common': 6.4.0-alpha.38 '@storybook/node-logger': 6.4.0-alpha.38 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/ui': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/theming': 6.4.0-alpha.38 + '@storybook/ui': 6.4.0-alpha.38 '@types/node': 16.11.6 babel-loader: 8.2.3_27ba53a5d4d1393445550229adea0ad0 case-sensitive-paths-webpack-plugin: 2.4.0 @@ -8371,8 +8281,6 @@ packages: fs-extra: 9.1.0 html-webpack-plugin: 5.3.2_webpack@5.61.0 node-fetch: 2.6.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c read-pkg-up: 7.0.1 regenerator-runtime: 0.13.9 resolve-from: 5.0.0 @@ -8380,7 +8288,6 @@ packages: telejson: 5.3.3 terser-webpack-plugin: 5.2.4_webpack@5.61.0 ts-dedent: 2.2.0 - typescript: 4.5.1-rc url-loader: 4.1.1_file-loader@6.2.0+webpack@5.61.0 util-deprecate: 1.0.2 webpack: 5.61.0 @@ -8422,32 +8329,30 @@ packages: core-js: 3.17.3 dev: true - /@storybook/preview-web/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/preview-web/6.4.0-alpha.38: resolution: {integrity: sha512-JNUAUzi1PV/CinvVs6DophrBi0+JPq8Xig6mt27A1RQ73iBggHU5LCAoAlawS/g2tsfHMTDSsQPaPd/rEnEh+A==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/channel-postmessage': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 - '@storybook/store': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/store': 6.4.0-alpha.38 ansi-to-html: 0.6.15 core-js: 3.17.3 global: 4.4.0 lodash: 4.17.21 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 unfetch: 4.2.0 util-deprecate: 1.0.2 dev: true - /@storybook/react-docgen-typescript-plugin/1.0.2-canary.253f8c1.0_917303960781c460306bcf6843300e8d: + /@storybook/react-docgen-typescript-plugin/1.0.2-canary.253f8c1.0_webpack@4.46.0: resolution: {integrity: sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==} peerDependencies: typescript: '>= 3.x' @@ -8458,15 +8363,14 @@ packages: find-cache-dir: 3.3.2 flat-cache: 3.0.4 micromatch: 4.0.4 - react-docgen-typescript: 2.1.1_typescript@4.5.1-rc + react-docgen-typescript: 2.1.1 tslib: 2.3.1 - typescript: 4.5.1-rc webpack: 4.46.0 transitivePeerDependencies: - supports-color dev: true - /@storybook/react/6.3.12_158e762f35d25e0f30388420e4124ec3: + /@storybook/react/6.3.12: resolution: {integrity: sha512-c1Y/3/eNzye+ZRwQ3BXJux6pUMVt3lhv1/M9Qagl9JItP3jDSj5Ed3JHCgwEqpprP8mvNNXwEJ8+M7vEQyDuHg==} engines: {node: '>=10.13.0'} hasBin: true @@ -8481,32 +8385,28 @@ packages: typescript: optional: true dependencies: - '@babel/core': 7.16.0 - '@babel/preset-flow': 7.16.0_@babel+core@7.16.0 - '@babel/preset-react': 7.16.0_@babel+core@7.16.0 + '@babel/preset-flow': 7.16.0 + '@babel/preset-react': 7.16.0 '@pmmmwh/react-refresh-webpack-plugin': 0.4.3_133f2312fd2dfba9fc3b3697533854a6 - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/core': 6.3.12_ca90ea5d8a9c7361c126c5d64363356d - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 + '@storybook/addons': 6.3.12 + '@storybook/core': 6.3.12_webpack@4.46.0 + '@storybook/core-common': 6.3.12 '@storybook/node-logger': 6.3.12 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0_917303960781c460306bcf6843300e8d + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0_webpack@4.46.0 '@storybook/semver': 7.3.2 '@types/webpack-env': 1.16.3 babel-plugin-add-react-displayname: 0.0.5 - babel-plugin-named-asset-import: 0.3.7_@babel+core@7.16.0 + babel-plugin-named-asset-import: 0.3.7 babel-plugin-react-docgen: 4.2.1 core-js: 3.19.1 global: 4.4.0 lodash: 4.17.21 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 react-dev-utils: 11.0.4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c react-refresh: 0.8.3 read-pkg-up: 7.0.1 regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 - typescript: 4.5.1-rc webpack: 4.46.0 transitivePeerDependencies: - '@storybook/builder-webpack5' @@ -8525,7 +8425,7 @@ packages: - webpack-plugin-serve dev: true - /@storybook/react/6.3.12_7c21731b976151a2ab0cda54216e1b22: + /@storybook/react/6.3.12_8a69853daa796dbcd7221fb09bd38bec: resolution: {integrity: sha512-c1Y/3/eNzye+ZRwQ3BXJux6pUMVt3lhv1/M9Qagl9JItP3jDSj5Ed3JHCgwEqpprP8mvNNXwEJ8+M7vEQyDuHg==} engines: {node: '>=10.13.0'} hasBin: true @@ -8540,31 +8440,29 @@ packages: typescript: optional: true dependencies: - '@babel/preset-flow': 7.16.0 - '@babel/preset-react': 7.16.0 + '@babel/core': 7.16.0 + '@babel/preset-flow': 7.16.0_@babel+core@7.16.0 + '@babel/preset-react': 7.16.0_@babel+core@7.16.0 '@pmmmwh/react-refresh-webpack-plugin': 0.4.3_133f2312fd2dfba9fc3b3697533854a6 - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/core': 6.3.12_892f44ca87711d14370428e777de45ce - '@storybook/core-common': 6.3.12_97850682f79266241e42764eb32e5172 + '@storybook/addons': 6.3.12 + '@storybook/core': 6.3.12_485bc28f394fa22a848285efd9af0be0 + '@storybook/core-common': 6.3.12 '@storybook/node-logger': 6.3.12 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0_917303960781c460306bcf6843300e8d + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0_webpack@4.46.0 '@storybook/semver': 7.3.2 '@types/webpack-env': 1.16.3 babel-plugin-add-react-displayname: 0.0.5 - babel-plugin-named-asset-import: 0.3.7 + babel-plugin-named-asset-import: 0.3.7_@babel+core@7.16.0 babel-plugin-react-docgen: 4.2.1 core-js: 3.19.1 global: 4.4.0 lodash: 4.17.21 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 react-dev-utils: 11.0.4 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c react-refresh: 0.8.3 read-pkg-up: 7.0.1 regenerator-runtime: 0.13.9 ts-dedent: 2.2.0 - typescript: 4.5.1-rc webpack: 4.46.0 transitivePeerDependencies: - '@storybook/builder-webpack5' @@ -8583,13 +8481,13 @@ packages: - webpack-plugin-serve dev: true - /@storybook/router/6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/router/6.3.12: resolution: {integrity: sha512-G/pNGCnrJRetCwyEZulHPT+YOcqEj/vkPVDTUfii2qgqukup6K0cjwgd7IukAURnAnnzTi1gmgFuEKUi8GE/KA==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@reach/router': 1.3.4_9a9fcfd9691ee39f83ac00f4a3221da4 + '@reach/router': 1.3.4 '@storybook/client-logger': 6.3.12 '@types/reach__router': 1.3.9 core-js: 3.19.1 @@ -8598,18 +8496,16 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c ts-dedent: 2.2.0 dev: true - /@storybook/router/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/router/6.4.0-alpha.38: resolution: {integrity: sha512-7ABZ+KqeDk7kS7msCw4W8t7vY7zF6/gCYLczGERGdjnCd3UoEoGc43lFeMOyO0RC+/adW/BuwYWOmxTrD7Zdfg==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@reach/router': 1.3.4_9a9fcfd9691ee39f83ac00f4a3221da4 + '@reach/router': 1.3.4 '@storybook/client-logger': 6.4.0-alpha.38 '@types/reach__router': 1.3.9 core-js: 3.17.3 @@ -8618,8 +8514,6 @@ packages: lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c ts-dedent: 2.2.0 dev: true @@ -8632,13 +8526,13 @@ packages: find-up: 4.1.0 dev: true - /@storybook/source-loader/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/source-loader/6.4.0-alpha.38: resolution: {integrity: sha512-vM0wjqHv3gs9OXKG5S8GQrKxNlPZjaSb2Qekvu2i5k4ALltHWTbam5n90LU7yp0Bff87EMAX5e78aY0A7GlNdg==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 core-js: 3.17.3 @@ -8647,15 +8541,13 @@ packages: loader-utils: 2.0.1 lodash: 4.17.21 prettier: 2.4.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c regenerator-runtime: 0.13.9 dev: true - /@storybook/store/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/store/6.4.0-alpha.38: resolution: {integrity: sha512-INcjwNeaD3J08gasZSJs+GNW6aSkTN2EH2CPylHcVUPOLANf4OYrDtPxc/MMUu4NQXKt8xi5OlC6NH89r5/aGA==} dependencies: - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/addons': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 '@storybook/csf': 0.0.2--canary.68887a1.0 @@ -8672,83 +8564,77 @@ packages: - react-dom dev: true - /@storybook/theming/6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/theming/6.3.12: resolution: {integrity: sha512-wOJdTEa/VFyFB2UyoqyYGaZdym6EN7RALuQOAMT6zHA282FBmKw8nL5DETHEbctpnHdcrMC/391teK4nNSrdOA==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c + '@emotion/core': 10.1.1 '@emotion/is-prop-valid': 0.8.8 - '@emotion/styled': 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + '@emotion/styled': 10.0.27_@emotion+core@10.1.1 '@storybook/client-logger': 6.3.12 core-js: 3.19.1 deep-object-diff: 1.1.0 - emotion-theming: 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + emotion-theming: 10.0.27_@emotion+core@10.1.1 global: 4.4.0 memoizerific: 1.11.3 polished: 4.1.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c resolve-from: 5.0.0 ts-dedent: 2.2.0 dev: true - /@storybook/theming/6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4: + /@storybook/theming/6.4.0-alpha.38: resolution: {integrity: sha512-9H/etvjPXtOsUSMmBNJhqh6odbkap0qjrHpsJt+tgQihIwd0H01DZM/nxPlQf1vRObrjG4PUfoakcCCEcEblNg==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c + '@emotion/core': 10.1.1 '@emotion/is-prop-valid': 0.8.8 - '@emotion/styled': 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + '@emotion/styled': 10.0.27_@emotion+core@10.1.1 '@storybook/client-logger': 6.4.0-alpha.38 core-js: 3.17.3 deep-object-diff: 1.1.0 - emotion-theming: 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + emotion-theming: 10.0.27_@emotion+core@10.1.1 global: 4.4.0 memoizerific: 1.11.3 polished: 4.1.3 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c resolve-from: 5.0.0 ts-dedent: 2.2.0 dev: true - /@storybook/ui/6.3.12_14da01773538ca517609d7bab0ada649: + /@storybook/ui/6.3.12: resolution: {integrity: sha512-PC2yEz4JMfarq7rUFbeA3hCA+31p5es7YPEtxLRvRwIZhtL0P4zQUfHpotb3KgWdoAIfZesAuoIQwMPQmEFYrw==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c - '@storybook/addons': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@emotion/core': 10.1.1 + '@storybook/addons': 6.3.12 + '@storybook/api': 6.3.12 '@storybook/channels': 6.3.12 '@storybook/client-logger': 6.3.12 - '@storybook/components': 6.3.12_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.3.12 '@storybook/core-events': 6.3.12 - '@storybook/router': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.3.12 '@storybook/semver': 7.3.2 - '@storybook/theming': 6.3.12_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.3.12 '@types/markdown-to-jsx': 6.11.3 copy-to-clipboard: 3.3.1 core-js: 3.19.1 core-js-pure: 3.19.1 - downshift: 6.1.7_c9c210d65bdac3c3f586a38a4275dd8c - emotion-theming: 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + downshift: 6.1.7 + emotion-theming: 10.0.27_@emotion+core@10.1.1 fuse.js: 3.6.1 global: 4.4.0 lodash: 4.17.21 - markdown-to-jsx: 6.11.4_c9c210d65bdac3c3f586a38a4275dd8c + markdown-to-jsx: 6.11.4 memoizerific: 1.11.3 polished: 4.1.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-draggable: 4.4.4_9a9fcfd9691ee39f83ac00f4a3221da4 - react-helmet-async: 1.1.2_9a9fcfd9691ee39f83ac00f4a3221da4 + react-draggable: 4.4.4 + react-helmet-async: 1.1.2 react-sizeme: 3.0.2 regenerator-runtime: 0.13.9 resolve-from: 5.0.0 @@ -8757,39 +8643,37 @@ packages: - '@types/react' dev: true - /@storybook/ui/6.4.0-alpha.38_14da01773538ca517609d7bab0ada649: + /@storybook/ui/6.4.0-alpha.38: resolution: {integrity: sha512-saa02fJEkuUCtcLAKevLeHt8tKMAuEHpOSbGDa2n8O/uglzf1bz9yjYeg+FwmNlxA2q2X5UM6A057eHSNwyfPQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c - '@storybook/addons': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 - '@storybook/api': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@emotion/core': 10.1.1 + '@storybook/addons': 6.4.0-alpha.38 + '@storybook/api': 6.4.0-alpha.38 '@storybook/channels': 6.4.0-alpha.38 '@storybook/client-logger': 6.4.0-alpha.38 - '@storybook/components': 6.4.0-alpha.38_14da01773538ca517609d7bab0ada649 + '@storybook/components': 6.4.0-alpha.38 '@storybook/core-events': 6.4.0-alpha.38 - '@storybook/router': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/router': 6.4.0-alpha.38 '@storybook/semver': 7.3.2 - '@storybook/theming': 6.4.0-alpha.38_9a9fcfd9691ee39f83ac00f4a3221da4 + '@storybook/theming': 6.4.0-alpha.38 copy-to-clipboard: 3.3.1 core-js: 3.17.3 core-js-pure: 3.17.3 - downshift: 6.1.3_c9c210d65bdac3c3f586a38a4275dd8c - emotion-theming: 10.0.27_29362b9726706a0ae276da7ff9e2fe66 + downshift: 6.1.3 + emotion-theming: 10.0.27_@emotion+core@10.1.1 fuse.js: 3.6.1 global: 4.4.0 lodash: 4.17.21 - markdown-to-jsx: 7.1.3_c9c210d65bdac3c3f586a38a4275dd8c + markdown-to-jsx: 7.1.3 memoizerific: 1.11.3 polished: 4.1.3 qs: 6.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-draggable: 4.4.4_9a9fcfd9691ee39f83ac00f4a3221da4 - react-helmet-async: 1.0.9_9a9fcfd9691ee39f83ac00f4a3221da4 - react-sizeme: 3.0.1_9a9fcfd9691ee39f83ac00f4a3221da4 + react-draggable: 4.4.4 + react-helmet-async: 1.0.9 + react-sizeme: 3.0.1 regenerator-runtime: 0.13.9 resolve-from: 5.0.0 store2: 2.12.0 @@ -8964,7 +8848,7 @@ packages: typechain: ^5.0.0 web3: ^1.0.0 dependencies: - typechain: 5.1.2_typescript@4.5.1-rc + typechain: 5.1.2 dev: false /@types/asn1js/2.0.2: @@ -9859,7 +9743,7 @@ packages: '@types/yargs-parser': 20.2.1 dev: true - /@typescript-eslint/eslint-plugin/5.3.0_c0f26c2804ddda4720e68667d05234b5: + /@typescript-eslint/eslint-plugin/5.3.0_@typescript-eslint+parser@5.3.0: resolution: {integrity: sha512-ARUEJHJrq85aaiCqez7SANeahDsJTD3AEua34EoQN9pHS6S5Bq9emcIaGGySt/4X2zSi+vF5hAH52sEen7IO7g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -9870,22 +9754,20 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.3.0_5ad87ec15ece8fc8da8d47a233a9a023 - '@typescript-eslint/parser': 5.3.0_5ad87ec15ece8fc8da8d47a233a9a023 + '@typescript-eslint/experimental-utils': 5.3.0 + '@typescript-eslint/parser': 5.3.0 '@typescript-eslint/scope-manager': 5.3.0 debug: 4.3.2 - eslint: 7.32.0 functional-red-black-tree: 1.0.1 ignore: 5.1.9 regexpp: 3.2.0 semver: 7.3.5 - tsutils: 3.21.0_typescript@4.5.1-rc - typescript: 4.5.1-rc + tsutils: 3.21.0 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils/5.3.0_5ad87ec15ece8fc8da8d47a233a9a023: + /@typescript-eslint/experimental-utils/5.3.0: resolution: {integrity: sha512-NFVxYTjKj69qB0FM+piah1x3G/63WB8vCBMnlnEHUsiLzXSTWb9FmFn36FD9Zb4APKBLY3xRArOGSMQkuzTF1w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -9894,16 +9776,15 @@ packages: '@types/json-schema': 7.0.9 '@typescript-eslint/scope-manager': 5.3.0 '@typescript-eslint/types': 5.3.0 - '@typescript-eslint/typescript-estree': 5.3.0_typescript@4.5.1-rc - eslint: 7.32.0 + '@typescript-eslint/typescript-estree': 5.3.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@7.32.0 + eslint-utils: 3.0.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser/5.3.0_5ad87ec15ece8fc8da8d47a233a9a023: + /@typescript-eslint/parser/5.3.0: resolution: {integrity: sha512-rKu/yAReip7ovx8UwOAszJVO5MgBquo8WjIQcp1gx4pYQCwYzag+I5nVNHO4MqyMkAo0gWt2gWUi+36gWAVKcw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -9915,10 +9796,8 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.3.0 '@typescript-eslint/types': 5.3.0 - '@typescript-eslint/typescript-estree': 5.3.0_typescript@4.5.1-rc + '@typescript-eslint/typescript-estree': 5.3.0 debug: 4.3.2 - eslint: 7.32.0 - typescript: 4.5.1-rc transitivePeerDependencies: - supports-color dev: true @@ -9936,7 +9815,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.3.0_typescript@4.5.1-rc: + /@typescript-eslint/typescript-estree/5.3.0: resolution: {integrity: sha512-FJ0nqcaUOpn/6Z4Jwbtf+o0valjBLkqc3MWkMvrhA2TvzFXtcclIM8F4MBEmYa2kgcI8EZeSAzwoSrIC8JYkug==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -9951,8 +9830,7 @@ packages: globby: 11.0.4 is-glob: 4.0.3 semver: 7.3.5 - tsutils: 3.21.0_typescript@4.5.1-rc - typescript: 4.5.1-rc + tsutils: 3.21.0 transitivePeerDependencies: - supports-color dev: true @@ -13299,7 +13177,7 @@ packages: safe-buffer: 5.2.1 sha.js: 2.4.11 - /create-react-context/0.3.0_9970b490fb16582c87a82f17acf5759d: + /create-react-context/0.3.0_prop-types@15.7.2: resolution: {integrity: sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==} peerDependencies: prop-types: ^15.0.0 @@ -13307,7 +13185,6 @@ packages: dependencies: gud: 1.0.0 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 warning: 4.0.3 dev: true @@ -14288,7 +14165,7 @@ packages: minimatch: 3.0.4 dev: false - /downshift/6.1.3_c9c210d65bdac3c3f586a38a4275dd8c: + /downshift/6.1.3: resolution: {integrity: sha512-RA1MuaNcTbt0j+sVLhSs8R2oZbBXYAtdQP/V+uHhT3DoDteZzJPjlC+LQVm9T07Wpvo84QXaZtUCePLDTDwGXg==} peerDependencies: react: '>=16.12.0' @@ -14296,11 +14173,10 @@ packages: '@babel/runtime': 7.16.0 compute-scroll-into-view: 1.0.17 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 react-is: 17.0.2 dev: true - /downshift/6.1.7_c9c210d65bdac3c3f586a38a4275dd8c: + /downshift/6.1.7: resolution: {integrity: sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg==} peerDependencies: react: '>=16.12.0' @@ -14308,7 +14184,6 @@ packages: '@babel/runtime': 7.16.0 compute-scroll-into-view: 1.0.17 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 react-is: 17.0.2 tslib: 2.3.1 dev: true @@ -14427,17 +14302,16 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} - /emotion-theming/10.0.27_29362b9726706a0ae276da7ff9e2fe66: + /emotion-theming/10.0.27_@emotion+core@10.1.1: resolution: {integrity: sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==} peerDependencies: '@emotion/core': ^10.0.27 react: '>=16.3.0' dependencies: '@babel/runtime': 7.16.0 - '@emotion/core': 10.1.1_c9c210d65bdac3c3f586a38a4275dd8c + '@emotion/core': 10.1.1 '@emotion/weak-memoize': 0.2.5 hoist-non-react-statics: 3.3.2 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /enc-utils/3.0.0: @@ -14925,6 +14799,15 @@ packages: eslint-visitor-keys: 1.3.0 dev: true + /eslint-utils/3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint-visitor-keys: 2.1.0 + dev: true + /eslint-utils/3.0.0_eslint@7.32.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} @@ -15987,7 +15870,7 @@ packages: tapable: 1.1.3 dev: true - /fork-ts-checker-webpack-plugin/6.4.0_ea712fb27c7b0f932a8b3dd814d4d586: + /fork-ts-checker-webpack-plugin/6.4.0_webpack@4.46.0: resolution: {integrity: sha512-3I3wFkc4DbzaUDPWEi96wdYGu4EKtxBafhZYm0o4mX51d9bphAY4P3mBl8K5mFXFJqVzHfmdbm9kLGnm7vwwBg==} engines: {node: '>=10', yarn: '>=1.0.0'} peerDependencies: @@ -16007,7 +15890,6 @@ packages: chokidar: 3.5.2 cosmiconfig: 6.0.0 deepmerge: 4.2.2 - eslint: 7.32.0 fs-extra: 9.1.0 glob: 7.2.0 memfs: 3.3.0 @@ -16015,7 +15897,6 @@ packages: schema-utils: 2.7.0 semver: 7.3.5 tapable: 1.1.3 - typescript: 4.5.1-rc webpack: 4.46.0 dev: true @@ -16638,7 +16519,7 @@ packages: yargs: 7.1.2 dev: true - /gulp-zip/5.1.0_gulp@4.0.2: + /gulp-zip/5.1.0: resolution: {integrity: sha512-XZr/y91IliK/SpR74g3TkZejGkGEmK7CSDjSghT1jXshgO+dFvpLIz9w9fpuwkew6i7k4F+G24TubNgq1ISzEw==} engines: {node: '>=8'} peerDependencies: @@ -16648,7 +16529,6 @@ packages: optional: true dependencies: get-stream: 5.2.0 - gulp: 4.0.2 plugin-error: 1.0.1 through2: 3.0.2 vinyl: 2.2.1 @@ -19450,24 +19330,21 @@ packages: resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} dev: true - /markdown-to-jsx/6.11.4_c9c210d65bdac3c3f586a38a4275dd8c: + /markdown-to-jsx/6.11.4: resolution: {integrity: sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw==} engines: {node: '>= 4'} peerDependencies: react: '>= 0.14.0' dependencies: prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 unquote: 1.1.1 dev: true - /markdown-to-jsx/7.1.3_c9c210d65bdac3c3f586a38a4275dd8c: + /markdown-to-jsx/7.1.3: resolution: {integrity: sha512-jtQ6VyT7rMT5tPV0g2EJakEnXLiPksnvlYtwQsVVZ611JsWGN8bQ1tVSDX4s6JllfEH6wmsYxNjTUAMrPmNA8w==} engines: {node: '>= 10'} peerDependencies: react: '>= 0.14.0' - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /matchdep/2.0.0: @@ -19757,7 +19634,7 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - /mini-create-react-context/0.4.1_9970b490fb16582c87a82f17acf5759d: + /mini-create-react-context/0.4.1_prop-types@15.7.2: resolution: {integrity: sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==} peerDependencies: prop-types: ^15.0.0 @@ -19765,7 +19642,6 @@ packages: dependencies: '@babel/runtime': 7.15.4 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 tiny-warning: 1.0.3 dev: false @@ -19998,7 +19874,7 @@ packages: resolution: {integrity: sha1-ulSMh578+5DaHE2eCX20pGySVe8=} dev: false - /nano-css/5.3.1_9a9fcfd9691ee39f83ac00f4a3221da4: + /nano-css/5.3.1: resolution: {integrity: sha512-ENPIyNzANQRyYVvb62ajDd7PAyIgS2LIUnT9ewih4yrXSZX4hKoUwssy8WjUH++kEOA5wUTMgNnV7ko5n34kUA==} peerDependencies: react: '*' @@ -20008,8 +19884,6 @@ packages: csstype: 3.0.8 fastest-stable-stringify: 2.0.2 inline-style-prefixer: 6.0.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c rtl-css-js: 1.14.2 sourcemap-codec: 1.4.8 stacktrace-js: 2.0.2 @@ -20208,7 +20082,7 @@ packages: engines: {node: '>=8'} dev: false - /notistack/2.0.3_4fde53ffa339abe904971fb02833fc6f: + /notistack/2.0.3: resolution: {integrity: sha512-krmVFtTO9kEY1Pa4NrbyexrjiRcV6TqBM2xLx8nuDea1g96Z/OZfkvVLmYKkTvoSJ3jyQntWK16z86ssW5kt4A==} peerDependencies: '@emotion/react': ^11.4.1 @@ -20222,13 +20096,8 @@ packages: '@emotion/styled': optional: true dependencies: - '@emotion/react': 11.5.0_6b5df8fda4c0b6d9d2f517da6b1996a3 - '@emotion/styled': 11.3.0_d36cd8dbf8213640c43ee9dfdf74e3f6 - '@mui/material': 5.0.6_bc348a80bfe5bdd02e3041dcfec8203f clsx: 1.1.1 hoist-non-react-statics: 3.3.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: false /now-and-later/2.0.1: @@ -21010,11 +20879,11 @@ packages: engines: {node: '>=4.0.0'} dev: false - /pnp-webpack-plugin/1.6.4_typescript@4.5.1-rc: + /pnp-webpack-plugin/1.6.4: resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} engines: {node: '>=6'} dependencies: - ts-pnp: 1.2.0_typescript@4.5.1-rc + ts-pnp: 1.2.0 transitivePeerDependencies: - typescript dev: true @@ -21607,7 +21476,7 @@ packages: webpack: 4.46.0 dev: true - /react-avatar-editor/12.0.0_23eba1549ad9a79a22241637c0deb6bc: + /react-avatar-editor/12.0.0_@babel+core@7.16.0: resolution: {integrity: sha512-l7NrN8CXlUXbMhnbkuduAtR3+AlDz+DzYWlYBNr7q+rNeJMZlv26ap3Dk/D1WK/MPlnoS33iITlhLkuDsYQpug==} peerDependencies: react: ^0.14.0 || ^17.0.0 @@ -21616,31 +21485,23 @@ packages: '@babel/plugin-transform-runtime': 7.15.0_@babel+core@7.16.0 '@babel/runtime': 7.15.4 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c transitivePeerDependencies: - '@babel/core' - supports-color dev: false - /react-colorful/5.4.0_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-colorful/5.4.0: resolution: {integrity: sha512-k7QJXuQGWevr/V8hoMJ1wBW9i2CVhBdDXpBf3jy/AAtzVyYtsFqEAT+y+NOGiSG1cmnGTreqm5EFLXlVaKbPLQ==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: true - /react-colorful/5.5.0_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-colorful/5.5.0: resolution: {integrity: sha512-BuzrlrM0ylg7coPkXOrRqlf2BgHLw5L44sybbr9Lg4xy7w9e5N7fGYbojOO0s8J0nvrM3PERN2rVFkvSa24lnQ==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: true /react-dev-utils/11.0.4: @@ -21683,12 +21544,10 @@ packages: - utf-8-validate dev: true - /react-docgen-typescript/2.1.1_typescript@4.5.1-rc: + /react-docgen-typescript/2.1.1: resolution: {integrity: sha512-XWe8bsYqVjxciKdpNoufaHiB7FgUHIOnVQgxUolRL3Zlof2zkdTzuQH6SU2n3Ek9kfy3O1c63ojMtNfpiuNeZQ==} peerDependencies: typescript: '>= 4.3.x' - dependencies: - typescript: 4.5.1-rc dev: true /react-docgen/5.4.0: @@ -21721,7 +21580,7 @@ packages: scheduler: 0.21.0-alpha-00ced1e2b-20211102 dev: false - /react-draggable/4.4.4_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-draggable/4.4.4: resolution: {integrity: sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==} peerDependencies: react: '>= 16.3.0' @@ -21729,10 +21588,8 @@ packages: dependencies: clsx: 1.1.1 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - /react-element-to-jsx-string/14.3.2_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-element-to-jsx-string/14.3.2: resolution: {integrity: sha512-WZbvG72cjLXAxV7VOuSzuHEaI3RHj10DZu8EcKQpkKcAj7+qAkG5XUeSdX5FXrA0vPrlx0QsnAzZEBJwzV0e+w==} peerDependencies: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 @@ -21740,8 +21597,6 @@ packages: dependencies: '@base2/pretty-print-object': 1.0.0 is-plain-object: 3.0.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: true /react-error-overlay/6.0.9: @@ -21752,16 +21607,15 @@ packages: resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==} dev: true - /react-feather/2.0.9_c9c210d65bdac3c3f586a38a4275dd8c: + /react-feather/2.0.9: resolution: {integrity: sha512-yMfCGRkZdXwIs23Zw/zIWCJO3m3tlaUvtHiXlW+3FH7cIT6fiK1iJ7RJWugXq7Fso8ZaQyUm92/GOOHXvkiVUw==} peerDependencies: react: ^16.8.6 || ^17 dependencies: prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: false - /react-helmet-async/1.0.9_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-helmet-async/1.0.9: resolution: {integrity: sha512-N+iUlo9WR3/u9qGMmP4jiYfaD6pe9IvDTapZLFJz2D3xlTlCM1Bzy4Ab3g72Nbajo/0ZyW+W9hdz8Hbe4l97pQ==} peerDependencies: react: ^16.6.0 || ^17.0.0 @@ -21770,13 +21624,11 @@ packages: '@babel/runtime': 7.16.0 invariant: 2.2.4 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c react-fast-compare: 3.2.0 shallowequal: 1.1.0 dev: true - /react-helmet-async/1.1.2_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-helmet-async/1.1.2: resolution: {integrity: sha512-LTTzDDkyIleT/JJ6T/uqx7Y8qi1EuPPSiJawQY/nHHz0h7SPDT6HxP1YDDQx/fzcVxCqpWEEMS3QdrSrNkJYhg==} peerDependencies: react: ^16.6.0 || ^17.0.0 @@ -21785,13 +21637,11 @@ packages: '@babel/runtime': 7.16.0 invariant: 2.2.4 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c react-fast-compare: 3.2.0 shallowequal: 1.1.0 dev: true - /react-highlight-words/0.17.0_c9c210d65bdac3c3f586a38a4275dd8c: + /react-highlight-words/0.17.0: resolution: {integrity: sha512-uX1Qh5IGjnLuJT0Zok234QDwRC8h4hcVMnB99Cb7aquB1NlPPDiWKm0XpSZOTdSactvnClCk8LOmVlP+75dgHA==} peerDependencies: react: ^0.14.0 || ^15.0.0 || ^16.0.0-0 || ^17.0.0-0 @@ -21799,15 +21649,12 @@ packages: highlight-words-core: 1.2.2 memoize-one: 4.0.3 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: false - /react-hook-form/7.18.1_c9c210d65bdac3c3f586a38a4275dd8c: + /react-hook-form/7.18.1: resolution: {integrity: sha512-T9Lv5nBnLzncEd2p87Bc0+LtNYS+ochURtyvw7Ln474xSGxoUjvVygXa3WPWTc/2lH1sw3VdGtSfNKC35vJd5A==} peerDependencies: react: ^16.8.0 || ^17 - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 dev: false /react-i18next/11.13.0_ce296dfed05ef4ff385cad6a3faacdf6: @@ -21822,7 +21669,7 @@ packages: react: 18.0.0-alpha-00ced1e2b-20211102 dev: false - /react-inspector/5.1.1_c9c210d65bdac3c3f586a38a4275dd8c: + /react-inspector/5.1.1: resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==} peerDependencies: react: ^16.8.4 || ^17.0.0 @@ -21830,7 +21677,6 @@ packages: '@babel/runtime': 7.16.0 is-dom: 1.1.0 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true /react-is/16.13.1: @@ -21843,7 +21689,7 @@ packages: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} dev: true - /react-popper-tooltip/3.1.1_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-popper-tooltip/3.1.1: resolution: {integrity: sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==} peerDependencies: react: ^16.6.0 || ^17.0.0 @@ -21851,19 +21697,16 @@ packages: dependencies: '@babel/runtime': 7.16.0 '@popperjs/core': 2.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-popper: 2.2.5_68e58ce00cbac60a9f92508dd5e6499a + react-popper: 2.2.5_@popperjs+core@2.10.1 dev: true - /react-popper/2.2.5_68e58ce00cbac60a9f92508dd5e6499a: + /react-popper/2.2.5_@popperjs+core@2.10.1: resolution: {integrity: sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==} peerDependencies: '@popperjs/core': ^2.0.0 react: ^16.8.0 || ^17 dependencies: '@popperjs/core': 2.10.1 - react: 18.0.0-alpha-00ced1e2b-20211102 react-fast-compare: 3.2.0 warning: 4.0.3 dev: true @@ -21878,7 +21721,7 @@ packages: engines: {node: '>=0.10.0'} dev: true - /react-router-dom/5.3.0_c9c210d65bdac3c3f586a38a4275dd8c: + /react-router-dom/5.3.0: resolution: {integrity: sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==} peerDependencies: react: '>=15' @@ -21887,13 +21730,12 @@ packages: history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-router: 5.2.1_c9c210d65bdac3c3f586a38a4275dd8c + react-router: 5.2.1 tiny-invariant: 1.1.0 tiny-warning: 1.0.3 dev: false - /react-router-dom/6.0.0-beta.4_ba36cda0091235ae5584a110a384179b: + /react-router-dom/6.0.0-beta.4_history@5.1.0: resolution: {integrity: sha512-yppoRR8S7FxNMG6OGFn9DPJBPLsjeIuQa7GYnkRlgOSTBSPhAQpD6z7rvRzZnesQ9r6W+ibD9RvnqTcna4w/Pg==} peerDependencies: history: '>=5' @@ -21901,12 +21743,10 @@ packages: react-dom: '>=16.8' dependencies: history: 5.1.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-router: 6.0.0-beta.4_63e1619e79ddca1f1ecc330403c2f112 + react-router: 6.0.0-beta.4_history@5.1.0 dev: false - /react-router/5.2.1_c9c210d65bdac3c3f586a38a4275dd8c: + /react-router/5.2.1: resolution: {integrity: sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==} peerDependencies: react: '>=15' @@ -21915,26 +21755,24 @@ packages: history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 - mini-create-react-context: 0.4.1_9970b490fb16582c87a82f17acf5759d + mini-create-react-context: 0.4.1_prop-types@15.7.2 path-to-regexp: 1.8.0 prop-types: 15.7.2 - react: 18.0.0-alpha-00ced1e2b-20211102 react-is: 16.13.1 tiny-invariant: 1.1.0 tiny-warning: 1.0.3 dev: false - /react-router/6.0.0-beta.4_63e1619e79ddca1f1ecc330403c2f112: + /react-router/6.0.0-beta.4_history@5.1.0: resolution: {integrity: sha512-48JRRZJOwmfOKM12Tv3WjmNkVb2NpSEgDTWC4+MEJaud0+eyLJxqy62CKzOydMlk7hrfRFpC/elUYSZAuyx3qA==} peerDependencies: history: '>=5' react: '>=16.8' dependencies: history: 5.1.0 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: false - /react-sizeme/3.0.1_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-sizeme/3.0.1: resolution: {integrity: sha512-9Hf1NLgSbny1bha77l9HwvwwxQUJxFUqi44Ih+y3evA+PezBpGdCGlnvye6avss2cIgs9PgdYgMnfuzJWn/RUw==} peerDependencies: react: ^0.14.0 || ^15.0.0-0 || ^16.0.0 || ^17.0.0 @@ -21942,8 +21780,6 @@ packages: dependencies: element-resize-detector: 1.2.3 invariant: 2.2.4 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c shallowequal: 1.1.0 throttle-debounce: 3.0.1 dev: true @@ -21957,7 +21793,7 @@ packages: throttle-debounce: 3.0.1 dev: true - /react-syntax-highlighter/13.5.3_c9c210d65bdac3c3f586a38a4275dd8c: + /react-syntax-highlighter/13.5.3: resolution: {integrity: sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==} peerDependencies: react: '>= 0.14.0' @@ -21966,24 +21802,34 @@ packages: highlight.js: 10.7.3 lowlight: 1.20.0 prismjs: 1.24.1 - react: 18.0.0-alpha-00ced1e2b-20211102 refractor: 3.4.0 dev: true - /react-textarea-autosize/8.3.3_6b5df8fda4c0b6d9d2f517da6b1996a3: + /react-textarea-autosize/8.3.3: resolution: {integrity: sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==} engines: {node: '>=10'} peerDependencies: react: ^16.8.0 || ^17.0.0 dependencies: '@babel/runtime': 7.16.0 - react: 18.0.0-alpha-00ced1e2b-20211102 - use-composed-ref: 1.1.0_c9c210d65bdac3c3f586a38a4275dd8c - use-latest: 1.2.0_6b5df8fda4c0b6d9d2f517da6b1996a3 + use-composed-ref: 1.1.0 + use-latest: 1.2.0 transitivePeerDependencies: - '@types/react' dev: true + /react-transition-group/4.4.2: + resolution: {integrity: sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + dependencies: + '@babel/runtime': 7.15.4 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.7.2 + dev: false + /react-transition-group/4.4.2_9a9fcfd9691ee39f83ac00f4a3221da4: resolution: {integrity: sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==} peerDependencies: @@ -21998,17 +21844,16 @@ packages: react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: false - /react-universal-interface/0.6.2_946f04496fafbe35779ae73653d62189: + /react-universal-interface/0.6.2_tslib@2.3.1: resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: react: '*' tslib: '*' dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 tslib: 2.3.1 dev: false - /react-use/15.3.8_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-use/15.3.8: resolution: {integrity: sha512-GeGcrmGuUvZrY5wER3Lnph9DSYhZt5nEjped4eKDq8BRGr2CnLf9bDQWG9RFc7oCPphnscUUdOovzq0E5F2c6Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -22020,10 +21865,8 @@ packages: fast-deep-equal: 3.1.3 fast-shallow-equal: 1.0.0 js-cookie: 2.2.1 - nano-css: 5.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-universal-interface: 0.6.2_946f04496fafbe35779ae73653d62189 + nano-css: 5.3.1 + react-universal-interface: 0.6.2_tslib@2.3.1 resize-observer-polyfill: 1.5.1 screenfull: 5.1.0 set-harmonic-interval: 1.0.1 @@ -22032,7 +21875,7 @@ packages: tslib: 2.3.1 dev: false - /react-use/17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-use/17.3.1: resolution: {integrity: sha512-hs7+tS4rRm1QLHPfanLCqXIi632tP4V7Sai1ENUP2WTufU6am++tU9uSw9YrNCFqbABiEv0ndKU1XCUcfu2tXA==} peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -22044,10 +21887,8 @@ packages: fast-deep-equal: 3.1.3 fast-shallow-equal: 1.0.0 js-cookie: 2.2.1 - nano-css: 5.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c - react-universal-interface: 0.6.2_946f04496fafbe35779ae73653d62189 + nano-css: 5.3.1 + react-universal-interface: 0.6.2_tslib@2.3.1 resize-observer-polyfill: 1.5.1 screenfull: 5.1.0 set-harmonic-interval: 1.0.1 @@ -22056,18 +21897,15 @@ packages: tslib: 2.3.1 dev: false - /react-virtualized-auto-sizer/1.0.6_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-virtualized-auto-sizer/1.0.6: resolution: {integrity: sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==} engines: {node: '>8.0.0'} peerDependencies: react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 - dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: false - /react-window/1.8.6_9a9fcfd9691ee39f83ac00f4a3221da4: + /react-window/1.8.6: resolution: {integrity: sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==} engines: {node: '>8.0.0'} peerDependencies: @@ -22076,8 +21914,6 @@ packages: dependencies: '@babel/runtime': 7.15.4 memoize-one: 5.2.1 - react: 18.0.0-alpha-00ced1e2b-20211102 - react-dom: 18.0.0-alpha-00ced1e2b-20211102_c9c210d65bdac3c3f586a38a4275dd8c dev: false /react/18.0.0-alpha-00ced1e2b-20211102: @@ -22736,7 +22572,7 @@ packages: fsevents: 2.3.2 dev: true - /rss3-next/0.6.17_typescript@4.5.1-rc: + /rss3-next/0.6.17: resolution: {integrity: sha512-UEVpr9somInaz8kreZjUjVmo0cay/Q24CQSo8QJogChlphUpFyMAJSXtC7xS2p67ZSXL9CWPtzoPZtQ4wh0hBg==} dependencies: axios: 0.21.1 @@ -22746,7 +22582,7 @@ packages: js-cookie: 3.0.1 tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 - typescript-is: 0.18.2_typescript@4.5.1-rc + typescript-is: 0.18.2 util: 0.12.4 transitivePeerDependencies: - bufferutil @@ -24444,12 +24280,10 @@ packages: resolution: {integrity: sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==} dev: true - /ts-essentials/7.0.2_typescript@4.5.1-rc: + /ts-essentials/7.0.2: resolution: {integrity: sha512-qWPVC1xZGdefbsgFP7tPo+bsgSA2ZIXL1XeEe5M2WoMZxIOr/HbsHxP/Iv75IFhiMHMDGL7cOOwi5SXcgx9mHw==} peerDependencies: typescript: '>=3.7.0' - dependencies: - typescript: 4.5.1-rc dev: false /ts-interface-checker/0.1.13: @@ -24486,6 +24320,34 @@ packages: yargs-parser: 20.2.9 dev: true + /ts-node/10.4.0: + resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.7.0 + '@tsconfig/node10': 1.0.8 + '@tsconfig/node12': 1.0.9 + '@tsconfig/node14': 1.0.1 + '@tsconfig/node16': 1.0.2 + acorn: 8.5.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + yn: 3.1.1 + dev: true + /ts-node/10.4.0_typescript@4.5.1-rc: resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} hasBin: true @@ -24546,7 +24408,7 @@ packages: yn: 3.1.1 dev: true - /ts-pnp/1.2.0_typescript@4.5.1-rc: + /ts-pnp/1.2.0: resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} engines: {node: '>=6'} peerDependencies: @@ -24554,8 +24416,6 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - typescript: 4.5.1-rc dev: true /ts-results/3.3.0: @@ -24617,12 +24477,10 @@ packages: typescript: 2.9.2 dev: false - /tss-react/2.0.1_@emotion+react@11.5.0: + /tss-react/2.0.1: resolution: {integrity: sha512-dvnXeVw5FzjWnZlFvOLMQhbU9y9AQMnA3++iXy6baMRTDXo6QmBc/kx23EDpNSWmtfDhu/xHVVg6gP7eU1sa6w==} peerDependencies: '@emotion/react': ^11.4.1 - dependencies: - '@emotion/react': 11.5.0_6b5df8fda4c0b6d9d2f517da6b1996a3 dev: false /tsutils/1.9.1_typescript@2.9.2: @@ -24642,14 +24500,13 @@ packages: typescript: 2.9.2 dev: false - /tsutils/3.21.0_typescript@4.5.1-rc: + /tsutils/3.21.0: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.5.1-rc /tty-browserify/0.0.0: resolution: {integrity: sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=} @@ -24731,7 +24588,7 @@ packages: /type/2.5.0: resolution: {integrity: sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==} - /typechain/5.1.2_typescript@4.5.1-rc: + /typechain/5.1.2: resolution: {integrity: sha512-FuaCxJd7BD3ZAjVJoO+D6TnqKey3pQdsqOBsC83RKYWKli5BDhdf0TPkwfyjt20TUlZvOzJifz+lDwXsRkiSKA==} hasBin: true dependencies: @@ -24744,7 +24601,7 @@ packages: lodash: 4.17.21 mkdirp: 1.0.4 prettier: 2.3.2 - ts-essentials: 7.0.2_typescript@4.5.1-rc + ts-essentials: 7.0.2 transitivePeerDependencies: - supports-color - typescript @@ -24788,15 +24645,14 @@ packages: typescript: 2.9.2 dev: false - /typescript-is/0.18.2_typescript@4.5.1-rc: + /typescript-is/0.18.2: resolution: {integrity: sha512-TXgcmHLbuYaKtwyGy/v+oFWi9sIlEUSMcHSuRbIH7OtUuaMP6/bOPwOMDuEVRtGQ62Yx1XMdxFGbax81nXDKjg==} engines: {node: '>=6.14.4'} peerDependencies: typescript: ^4.1.5 dependencies: nested-error-stacks: 2.1.0 - tsutils: 3.21.0_typescript@4.5.1-rc - typescript: 4.5.1-rc + tsutils: 3.21.0 optionalDependencies: reflect-metadata: 0.1.13 dev: false @@ -25179,16 +25035,15 @@ packages: resolution: {integrity: sha512-12c4Vi40DHVdZ/8mOLjZjp0asCzM6hi8Gj116fpImRP1FN4gBMCtMi9XhLNOmre/FEQYNqHbZmX8iyYAtIcy8Q==} dev: false - /use-composed-ref/1.1.0_c9c210d65bdac3c3f586a38a4275dd8c: + /use-composed-ref/1.1.0: resolution: {integrity: sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==} peerDependencies: react: ^16.8.0 || ^17.0.0 dependencies: - react: 18.0.0-alpha-00ced1e2b-20211102 ts-essentials: 2.0.12 dev: true - /use-isomorphic-layout-effect/1.1.1_6b5df8fda4c0b6d9d2f517da6b1996a3: + /use-isomorphic-layout-effect/1.1.1: resolution: {integrity: sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==} peerDependencies: '@types/react': '*' @@ -25196,12 +25051,9 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 17.0.34 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: true - /use-latest/1.2.0_6b5df8fda4c0b6d9d2f517da6b1996a3: + /use-latest/1.2.0: resolution: {integrity: sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==} peerDependencies: '@types/react': '*' @@ -25210,18 +25062,15 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 17.0.34 - react: 18.0.0-alpha-00ced1e2b-20211102 - use-isomorphic-layout-effect: 1.1.1_6b5df8fda4c0b6d9d2f517da6b1996a3 + use-isomorphic-layout-effect: 1.1.1 dev: true - /use-subscription/1.5.1_c9c210d65bdac3c3f586a38a4275dd8c: + /use-subscription/1.5.1: resolution: {integrity: sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==} peerDependencies: react: ^16.8.0 || ^17.0.0 dependencies: object-assign: 4.1.1 - react: 18.0.0-alpha-00ced1e2b-20211102 dev: false /use/3.1.1: From 5202f5d6ac4f0039c45f2ec5de739fdc919d0178 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 10 Nov 2021 14:01:28 +0800 Subject: [PATCH 20/41] fix: EVM context --- .../src/initialization/Dashboard.tsx | 6 ++++ packages/mask/src/UIRoot.tsx | 26 ++++++++++++---- .../src/plugins/EVM/UI/Web3State/index.ts | 15 ++++++++++ .../SNSAdaptor/WalletStatusDialog/index.tsx | 17 +++++++++-- packages/plugin-infra/src/context/index.tsx | 16 +++++----- .../src/hooks/useRegisteredPluginNetwork.ts | 4 +-- .../src/hooks/useRegisteredPluginProvider.ts | 6 ++-- packages/plugin-infra/src/types.ts | 30 ++++++++++++------- .../plugin-infra/src/web3/useTokenPrice.ts | 4 +-- .../src/UI/components/ImageIcon/index.tsx | 2 -- .../src/UI/components/WalletIcon/index.tsx | 10 ++++--- packages/web3-shared/evm/context/hotfix.ts | 3 ++ packages/web3-shared/evm/package.json | 1 + 13 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 packages/web3-shared/evm/context/hotfix.ts diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index f51def04bc9f..9168f98d3ba0 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -11,6 +11,7 @@ import { import { ErrorBoundary } from '@masknet/shared' import { createInjectHooksRenderer, + NetworkPluginID, PluginsWeb3ContextProvider, useActivatedPluginsDashboard, useAllPluginsWeb3State, @@ -25,6 +26,7 @@ import { Pages } from '../pages/routes' import { Web3Context } from '../web3/context' import { useAppearance, usePluginID } from '../pages/Personas/api' import { PersonaContext } from '../pages/Personas/hooks/usePersonaContext' +import { fixWeb3State } from '../../../mask/src/plugins/EVM/UI/Web3State' const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) => x.GlobalInjection) @@ -32,6 +34,10 @@ export default function DashboardRoot() { const pluginID = usePluginID() const PluginsWeb3State = useAllPluginsWeb3State() + // TODO: + // migrate EVM plugin + fixWeb3State(PluginsWeb3State[NetworkPluginID.PLUGIN_EVM], Web3Context) + //#region theme const appearance = useAppearance() const mode = useSystemPreferencePalette() diff --git a/packages/mask/src/UIRoot.tsx b/packages/mask/src/UIRoot.tsx index ee0ec1796371..def43b632bec 100644 --- a/packages/mask/src/UIRoot.tsx +++ b/packages/mask/src/UIRoot.tsx @@ -1,14 +1,17 @@ +import { Suspense } from 'react' import { I18nextProvider } from 'react-i18next' -import { CssBaseline, StyledEngineProvider, Theme, ThemeProvider } from '@mui/material' -import { Web3Provider } from '@masknet/web3-shared-evm' import { CustomSnackbarProvider } from '@masknet/theme' -import { ErrorBoundary, ErrorBoundaryBuildInfoContext } from '@masknet/shared' +import { Web3Provider } from '@masknet/web3-shared-evm' +import { CssBaseline, StyledEngineProvider, Theme, ThemeProvider } from '@mui/material' +import { NetworkPluginID, PluginsWeb3ContextProvider, useAllPluginsWeb3State } from '@masknet/plugin-infra' +import { ErrorBoundary, ErrorBoundaryBuildInfoContext, useValueRef } from '@masknet/shared' import i18nNextInstance from './utils/i18n-next' import { Web3Context } from './web3/context' import { buildInfoMarkdown } from './extension/background-script/Jobs/PrintBuildFlags' -import { Suspense } from 'react' import { activatedSocialNetworkUI } from './social-network' import { FACEBOOK_ID } from './social-network-adaptor/facebook.com/base' +import { pluginIDSettings } from './settings/settings' +import { fixWeb3State } from './plugins/EVM/UI/Web3State' const identity = (jsx: React.ReactNode) => jsx as JSX.Element function compose(init: React.ReactNode, ...f: ((children: React.ReactNode) => JSX.Element)[]) { @@ -49,12 +52,25 @@ export interface MaskUIRootProps extends React.PropsWithChildren<{}> { } export function MaskUIRoot({ children, kind, useTheme }: MaskUIRootProps) { + const pluginID = useValueRef(pluginIDSettings) + const PluginsWeb3State = useAllPluginsWeb3State() + + // TODO: + // migrate EVM plugin + fixWeb3State(PluginsWeb3State[NetworkPluginID.PLUGIN_EVM], Web3Context) + + if (Object.values(NetworkPluginID).some((x) => !PluginsWeb3State[x])) return null + return compose( children, (jsx) => , (jsx) => , (jsx) => , - (jsx) => , + (jsx) => ( + + + + ), (jsx) => , kind === 'page' ? (jsx) => : identity, (jsx) => ( diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index a4107c3fecb3..9753df422ab3 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,3 +1,18 @@ import type { Plugin } from '@masknet/plugin-infra' +import type { Web3ProviderType } from '@masknet/web3-shared-evm' export const Web3State: Plugin.Shared.Web3State = {} + +export function fixWeb3State(state?: Plugin.Shared.Web3State, context?: Web3ProviderType) { + if (!state || !context) return + state.Shared = state.Shared ?? { + allowTestnet: context.allowTestnet, + account: context.account, + balance: context.balance, + blockNumber: context.blockNumber, + chainId: context.chainId, + networkType: context.networkType, + providerType: context.providerType, + } + return state +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx index 5c940d2126ed..b4a958f05cd8 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx @@ -19,12 +19,19 @@ import classNames from 'classnames' import { useCallback } from 'react' import { Copy, Edit3, ExternalLink } from 'react-feather' import { useCopyToClipboard } from 'react-use' +import { getMaskColor } from '@masknet/theme' +import { + useNetworkType, + useProviderType, + useRegisteredPluginNetwork, + useRegisteredPluginProvider, +} from '@masknet/plugin-infra' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import Services from '../../../../extension/service' import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' import { currentProviderSettings } from '../../settings' -import { getMaskColor } from '@masknet/theme' +import { pluginIDSettings } from '../../../../settings/settings' const useStyles = makeStyles()((theme) => ({ content: { @@ -103,6 +110,12 @@ export function WalletStatusDialog(props: WalletStatusDialogProps) { const selectedWallet = useWallet() const selectedProviderType = useValueRef(currentProviderSettings) + const pluginID = useValueRef(pluginIDSettings) + const networkType = useNetworkType() + const providerType = useProviderType() + const network = useRegisteredPluginNetwork(pluginID, networkType) + const provider = useRegisteredPluginProvider(pluginID, providerType) + //#region copy addr to clipboard const [, copyToClipboard] = useCopyToClipboard() const onCopy = useSnackbarCallback( @@ -155,7 +168,7 @@ export function WalletStatusDialog(props: WalletStatusDialogProps) {
    - +
    {selectedWallet.name} diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 8528fe6a69e5..81ff75277657 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -2,21 +2,19 @@ import React, { createContext, useContext } from 'react' import { createContainer } from 'unstated-next' import { useSubscription } from 'use-subscription' import type { Plugin } from '..' +import { CurrencyType, NetworkPluginID } from '../types' import { createConstantSubscription } from '../utils' -// network plugins -const PLUGIN_EVM_ID = 'com.maskbook.evm' -const PLUGIN_FLOW_ID = 'com.maskbook.flow' - // constant subscriptions const ZERO = createConstantSubscription(0) const ZERO_STRING = createConstantSubscription('0') +const USD_CURRENCY = createConstantSubscription(CurrencyType.USD) const EMPTY_STRING = createConstantSubscription('') const EMPTY_ARRAY = createConstantSubscription([]) const FALSE = createConstantSubscription(false) const NULL = createConstantSubscription(null) -const PluginIDContext = createContext(PLUGIN_EVM_ID) +const PluginIDContext = createContext(NetworkPluginID.PLUGIN_EVM) const PluginsWeb3Context = createContext>(null!) @@ -42,7 +40,7 @@ function usePluginWeb3State(pluginID: string, context: Record>) { return ( - + {children} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts index 77dc42e205a9..ec454d3cc859 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts @@ -1,5 +1,5 @@ import { useRegisteredPlugin } from '.' -export function useRegisteredPluginNetwork(pluginID: string, networkType?: string) { - return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.type === networkType) +export function useRegisteredPluginNetwork(pluginID: string, networkTypeOrID?: string) { + return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.type === networkTypeOrID || x.ID === networkTypeOrID) } diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts index 7682c20f7e9f..e2b5699b4f6c 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts @@ -1,5 +1,7 @@ import { useRegisteredPlugin } from '.' -export function useRegisteredPluginProvider(pluginID: string, providerID: string) { - return useRegisteredPlugin(pluginID)?.providers?.find((x) => x.ID === providerID) +export function useRegisteredPluginProvider(pluginID: string, providerTypeOrID?: string) { + return useRegisteredPlugin(pluginID)?.providers?.find( + (x) => x.ID === providerTypeOrID || x.type === providerTypeOrID, + ) } diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index bc1082ece5a4..8569596e4062 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -217,17 +217,6 @@ export namespace Plugin.Shared { } } - export enum CurrencyType { - NATIVE = 'native', - BTC = 'btc', - USD = 'usd', - } - - export enum TokenType { - Fungible = 'Fungible', - NonFungible = 'NonFungible', - } - export interface CryptoPrice { [token: string]: { [key in CurrencyType]: number @@ -698,6 +687,25 @@ export enum CurrentSNSNetwork { Instagram = 3, } +/** + * A network plugin defines the way to connect to a single chain. + */ +export enum NetworkPluginID { + PLUGIN_EVM = 'com.maskbook.evm', + PLUGIN_FLOW = 'com.maskbook.flow', +} + +export enum CurrencyType { + NATIVE = 'native', + BTC = 'btc', + USD = 'usd', +} + +export enum TokenType { + Fungible = 'Fungible', + NonFungible = 'NonFungible', +} + /** * This namespace is not related to the plugin authors */ diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts index 415f47d749a3..b123fd23275d 100644 --- a/packages/plugin-infra/src/web3/useTokenPrice.ts +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -1,7 +1,7 @@ -import type { Plugin } from '..' +import type { CurrencyType } from '../types' import { usePluginWeb3StateContext } from '../context' export function useTokenPrice(id: string, currencyType: string, pluginID?: string) { const { prices } = usePluginWeb3StateContext(pluginID) ?? {} - return prices?.[id][currencyType as Plugin.Shared.CurrencyType] ?? 0 + return prices?.[id][currencyType as CurrencyType] ?? 0 } diff --git a/packages/shared/src/UI/components/ImageIcon/index.tsx b/packages/shared/src/UI/components/ImageIcon/index.tsx index 217749d104aa..3836785e2bda 100644 --- a/packages/shared/src/UI/components/ImageIcon/index.tsx +++ b/packages/shared/src/UI/components/ImageIcon/index.tsx @@ -4,8 +4,6 @@ import { useStylesExtends } from '../..' const useStyles = makeStyles()((theme) => { return { icon: { - width: '100%', - height: '100%', borderRadius: '50%', backgroundColor: theme.palette.background.paper, }, diff --git a/packages/shared/src/UI/components/WalletIcon/index.tsx b/packages/shared/src/UI/components/WalletIcon/index.tsx index 9ee3e4bccb06..c549493140bb 100644 --- a/packages/shared/src/UI/components/WalletIcon/index.tsx +++ b/packages/shared/src/UI/components/WalletIcon/index.tsx @@ -22,8 +22,8 @@ const useStyles = makeStyles()({ interface WalletIconProps { size?: number badgeSize?: number - networkIcon: string - providerIcon: string + networkIcon?: string + providerIcon?: string } export const WalletIcon = ({ size = 24, badgeSize = 14, networkIcon, providerIcon }: WalletIconProps) => { @@ -35,8 +35,10 @@ export const WalletIcon = ({ size = 24, badgeSize = 14, networkIcon, providerIco height: size, width: size, }}> - - + {networkIcon ? : null} + {providerIcon ? ( + + ) : null}
    ) } diff --git a/packages/web3-shared/evm/context/hotfix.ts b/packages/web3-shared/evm/context/hotfix.ts new file mode 100644 index 000000000000..70bed9c3a250 --- /dev/null +++ b/packages/web3-shared/evm/context/hotfix.ts @@ -0,0 +1,3 @@ +import type { Plugin } from '@masknet/plugin-infura' + +export function hotfixWeb3StateEVM(web3State: Plugin.Shared.Web3State) {} diff --git a/packages/web3-shared/evm/package.json b/packages/web3-shared/evm/package.json index d3a461d3543f..76fa714e1fd3 100644 --- a/packages/web3-shared/evm/package.json +++ b/packages/web3-shared/evm/package.json @@ -8,6 +8,7 @@ "@ensdomains/address-encoder": "^0.2.6", "@masknet/web3-constants": "workspace:*", "@masknet/web3-contracts": "workspace:*", + "@masknet/web3-contracts": "workspace:*", "@unstoppabledomains/resolution": "^5.0.1", "bignumber.js": "9.0.1", "ethereum-blockies": "^0.1.1", From 04d0ba9b3b963a46ae38774298485a89079740fa Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 10 Nov 2021 15:06:22 +0800 Subject: [PATCH 21/41] fix: remove unused file --- packages/web3-shared/evm/context/hotfix.ts | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 packages/web3-shared/evm/context/hotfix.ts diff --git a/packages/web3-shared/evm/context/hotfix.ts b/packages/web3-shared/evm/context/hotfix.ts deleted file mode 100644 index 70bed9c3a250..000000000000 --- a/packages/web3-shared/evm/context/hotfix.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Plugin } from '@masknet/plugin-infura' - -export function hotfixWeb3StateEVM(web3State: Plugin.Shared.Web3State) {} From 5ec2dc99ff406a5250b210b35eb2b6e65711a782 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 10 Nov 2021 15:08:40 +0800 Subject: [PATCH 22/41] fix: ts error --- packages/mask/src/settings/listener.ts | 2 -- packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts | 4 ++-- packages/shared-base/src/Messages/Mask.ts | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mask/src/settings/listener.ts b/packages/mask/src/settings/listener.ts index 5442b2a6fe0d..5778aa0d1f4a 100644 --- a/packages/mask/src/settings/listener.ts +++ b/packages/mask/src/settings/listener.ts @@ -1,6 +1,4 @@ -import type { ValueRef } from '@dimensiondev/holoflows-kit' import { - allPostReplacementSettings, appearanceSettings, pluginIDSettings, networkIDSettings, diff --git a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts index 569a9e6d1375..19f68aa8f6f6 100644 --- a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts +++ b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts @@ -3,10 +3,10 @@ import { Plugin, useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor } f export function useAllPluginsWeb3State() { const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() const pluginsDashboard = useActivatedPluginsDashboard() - return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce((accumulator, current) => { + return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce>((accumulator, current) => { if (current.Web3State) { accumulator[current.ID] = current.Web3State } return accumulator - }, {} as Record) + }, {}) } diff --git a/packages/shared-base/src/Messages/Mask.ts b/packages/shared-base/src/Messages/Mask.ts index 9e0d725a2488..43503e946143 100644 --- a/packages/shared-base/src/Messages/Mask.ts +++ b/packages/shared-base/src/Messages/Mask.ts @@ -14,6 +14,8 @@ export interface MaskSettingsEvents { appearanceSettings: Appearance languageSettings: LanguageOptions debugModeSetting: boolean + pluginIDSettings: string + networkIDSettings: string currentChainIdSettings: number currentBalanceSettings: string currentBlockNumberSettings: number From a1863883da104fc967b7b01a75e952bcfda799e2 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 15 Nov 2021 10:25:01 +0800 Subject: [PATCH 23/41] fix: ts error --- .../src/components/shared/WalletStatusBox.tsx | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index 48be775115f1..c9331261dde9 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -1,16 +1,21 @@ -import { FormattedAddress, useRemoteControlledDialog, useValueRef, useSnackbarCallback } from '@masknet/shared' -import { WalletMessages } from '../../plugins/Wallet/messages' -import classNames from 'classnames' -import { currentProviderSettings } from '../../plugins/Wallet/settings' +import { useCallback } from 'react' import { useCopyToClipboard } from 'react-use' import { Copy, ExternalLink } from 'react-feather' -import { useI18N } from '../../utils' -import Services from '../../extension/service' +import classNames from 'classnames' import { ProviderType, resolveAddressLinkOnExplorer, useWallet, useChainId } from '@masknet/web3-shared-evm' import { Button, Link, Typography } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' -import { WalletIcon } from './WalletIcon' -import { useCallback } from 'react' +import { + FormattedAddress, + useRemoteControlledDialog, + useValueRef, + useSnackbarCallback, + WalletIcon, +} from '@masknet/shared' +import { WalletMessages } from '../../plugins/Wallet/messages' +import { currentProviderSettings } from '../../plugins/Wallet/settings' +import { useI18N } from '../../utils' +import Services from '../../extension/service' const useStyles = makeStyles()((theme) => ({ content: { From 063358e667b8d6aeca7dd143ffd52bc44924ceaa Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 13:38:14 +0800 Subject: [PATCH 24/41] refactor: rename some types --- .../src/plugins/EVM/UI/Web3State/index.ts | 6 +- .../mask/src/plugins/EVM/UI/Web3UI/index.tsx | 4 +- .../UI/components/ProviderIconClickBait.tsx | 6 +- packages/mask/src/plugins/EVM/base.ts | 4 +- packages/mask/src/plugins/EVM/constants.ts | 37 +-- packages/mask/src/plugins/ITO/base.ts | 2 +- packages/mask/src/plugins/RedPacket/base.ts | 2 +- .../mask/src/plugins/UnlockProtocol/base.ts | 2 +- .../PluginNetworkWatcher.tsx | 7 +- .../PluginProviderRender.tsx | 27 +- packages/plugin-infra/src/context/index.tsx | 9 +- .../src/hooks/useAllPluginsWeb3State.ts | 4 +- .../src/hooks/useRegisteredPluginNetwork.ts | 4 +- .../src/hooks/useRegisteredPluginProvider.ts | 2 +- packages/plugin-infra/src/index.ts | 1 + .../plugin-infra/src/manager/sns-adaptor.ts | 2 +- packages/plugin-infra/src/manager/store.ts | 4 +- packages/plugin-infra/src/types.ts | 286 +----------------- packages/plugin-infra/src/web3-types.ts | 258 ++++++++++++++++ .../plugin-infra/src/web3/useTokenPrice.ts | 2 +- .../plugins/Flow/src/UI/Web3State/index.ts | 4 +- packages/plugins/Flow/src/UI/Web3UI/index.tsx | 4 +- .../UI/components/ProviderIconClickBait.tsx | 6 +- packages/plugins/Flow/src/base.ts | 4 +- packages/plugins/Flow/src/constants.ts | 14 +- 25 files changed, 354 insertions(+), 347 deletions(-) create mode 100644 packages/plugin-infra/src/web3-types.ts diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index 9753df422ab3..54958b1aa956 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,9 +1,9 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import type { Web3ProviderType } from '@masknet/web3-shared-evm' -export const Web3State: Plugin.Shared.Web3State = {} +export const Web3State: Web3Plugin.Web3State = {} -export function fixWeb3State(state?: Plugin.Shared.Web3State, context?: Web3ProviderType) { +export function fixWeb3State(state?: Web3Plugin.Web3State, context?: Web3ProviderType) { if (!state || !context) return state.Shared = state.Shared ?? { allowTestnet: context.allowTestnet, diff --git a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx index 4982f2d52a6b..b8ed3c6fa77e 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx @@ -1,7 +1,7 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UI: Plugin.Shared.Web3UI = { +export const Web3UI: Web3Plugin.Web3UI = { SelectProviderDialog: { ProviderIconClickBait, }, diff --git a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx index c279760fd891..90deed735bd4 100644 --- a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx +++ b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx @@ -1,6 +1,6 @@ import { useCallback, cloneElement, isValidElement } from 'react' import { unreachable } from '@dimensiondev/kit' -import type { Plugin } from '@masknet/plugin-infra/src' +import type { Web3Plugin } from '@masknet/plugin-infra/src' import { PopupRoutes } from '@masknet/shared-base' import { useRemoteControlledDialog } from '@masknet/shared' import { getChainIdFromNetworkType, NetworkType, ProviderType, useWallets } from '@masknet/web3-shared-evm' @@ -8,8 +8,8 @@ import Services from '../../../../extension/service' import { WalletMessages } from '../../../Wallet/messages' export interface ProviderIconClickBaitProps { - network: Plugin.Shared.Network - provider: Plugin.Shared.Provider + network: Web3Plugin.NetworkDescriptor + provider: Web3Plugin.ProviderDescriptor children?: React.ReactNode } diff --git a/packages/mask/src/plugins/EVM/base.ts b/packages/mask/src/plugins/EVM/base.ts index 3a6031de0aa9..e1c2c6201f01 100644 --- a/packages/mask/src/plugins/EVM/base.ts +++ b/packages/mask/src/plugins/EVM/base.ts @@ -12,6 +12,6 @@ export const base: Plugin.Shared.Definition = { networks: { type: 'opt-out', networks: {} }, target: 'stable', }, - networks: PLUGIN_NETWORKS, - providers: PLUGIN_PROVIDERS, + declareWeb3Networks: PLUGIN_NETWORKS, + declareWeb3Providers: PLUGIN_PROVIDERS, } diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts index 10c8ba9eed89..bf14d87f6872 100644 --- a/packages/mask/src/plugins/EVM/constants.ts +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -1,3 +1,4 @@ +import type { Web3Plugin } from '@masknet/plugin-infra/src' import { NetworkType, ProviderType } from '@masknet/web3-shared-evm' export const PLUGIN_META_KEY = 'com.maskbook.evm' @@ -5,63 +6,63 @@ export const PLUGIN_ID = 'com.maskbook.evm' export const PLUGIN_NAME = 'EVM' export const PLUGIN_ICON = 'Ξ' export const PLUGIN_DESCRIPTION = '' -export const PLUGIN_NETWORKS = [ +export const PLUGIN_NETWORKS: Web3Plugin.NetworkDescriptor[] = [ { ID: `${PLUGIN_ID}_ethereum`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.Ethereum, name: 'Ethereum', - icon: new URL('./assets/ethereum.png', import.meta.url).toString(), + icon: new URL('./assets/ethereum.png', import.meta.url), }, { ID: `${PLUGIN_ID}_bsc`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.Binance, name: 'BSC', - icon: new URL('./assets/binance.png', import.meta.url).toString(), + icon: new URL('./assets/binance.png', import.meta.url), }, { ID: `${PLUGIN_ID}_polygon`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.Polygon, name: 'Polygon', - icon: new URL('./assets/polygon.png', import.meta.url).toString(), + icon: new URL('./assets/polygon.png', import.meta.url), }, { ID: `${PLUGIN_ID}_arbitrum`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.Arbitrum, name: 'Arbitrum One', - icon: new URL('./assets/arbitrum.png', import.meta.url).toString(), + icon: new URL('./assets/arbitrum.png', import.meta.url), }, { ID: `${PLUGIN_ID}_xdai`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.xDai, name: 'xDai', - icon: new URL('./assets/xdai.png', import.meta.url).toString(), + icon: new URL('./assets/xdai.png', import.meta.url), }, ] -export const PLUGIN_PROVIDERS = [ +export const PLUGIN_PROVIDERS: Web3Plugin.ProviderDescriptor[] = [ { ID: `${PLUGIN_ID}_maskwallet`, - pluginID: PLUGIN_ID, + providerAdaptorPluginID: PLUGIN_ID, type: ProviderType.MaskWallet, name: 'Mask Network', - icon: new URL('./assets/maskwallet.png', import.meta.url).toString(), + icon: new URL('./assets/maskwallet.png', import.meta.url), }, { ID: `${PLUGIN_ID}_metamask`, - pluginID: PLUGIN_ID, + providerAdaptorPluginID: PLUGIN_ID, type: ProviderType.MetaMask, name: 'MetaMask', - icon: new URL('./assets/metamask.png', import.meta.url).toString(), + icon: new URL('./assets/metamask.png', import.meta.url), }, { ID: `${PLUGIN_ID}_walletconnect`, - pluginID: PLUGIN_ID, + providerAdaptorPluginID: PLUGIN_ID, type: ProviderType.WalletConnect, name: 'WalletConnect', - icon: new URL('./assets/walletconnect.png', import.meta.url).toString(), + icon: new URL('./assets/walletconnect.png', import.meta.url), }, ] diff --git a/packages/mask/src/plugins/ITO/base.ts b/packages/mask/src/plugins/ITO/base.ts index bce8360ab138..6fee6402467f 100644 --- a/packages/mask/src/plugins/ITO/base.ts +++ b/packages/mask/src/plugins/ITO/base.ts @@ -15,7 +15,7 @@ export const base: Plugin.Shared.Definition = { networks: { type: 'opt-out', networks: {} }, target: 'stable', web3: { - operatingSupportedChains: [ + supportedOperationalChains: [ ChainId.Mainnet, ChainId.BSC, ChainId.Matic, diff --git a/packages/mask/src/plugins/RedPacket/base.ts b/packages/mask/src/plugins/RedPacket/base.ts index be212cf0834d..eb09ce8003e9 100644 --- a/packages/mask/src/plugins/RedPacket/base.ts +++ b/packages/mask/src/plugins/RedPacket/base.ts @@ -16,7 +16,7 @@ export const base: Plugin.Shared.Definition = { networks: { type: 'opt-out', networks: {} }, target: 'stable', web3: { - operatingSupportedChains: [ChainId.Mainnet, ChainId.BSC, ChainId.Matic, ChainId.Arbitrum, ChainId.xDai], + supportedOperationalChains: [ChainId.Mainnet, ChainId.BSC, ChainId.Matic, ChainId.Arbitrum, ChainId.xDai], }, }, } diff --git a/packages/mask/src/plugins/UnlockProtocol/base.ts b/packages/mask/src/plugins/UnlockProtocol/base.ts index 84e4f26d6a7b..34706cbf592f 100644 --- a/packages/mask/src/plugins/UnlockProtocol/base.ts +++ b/packages/mask/src/plugins/UnlockProtocol/base.ts @@ -13,7 +13,7 @@ export const base: Plugin.Shared.Definition = { networks: { type: 'opt-out', networks: {} }, target: 'stable', web3: { - operatingSupportedChains: [ChainId.Mainnet, ChainId.xDai, ChainId.Matic, ChainId.Rinkeby], + supportedOperationalChains: [ChainId.Mainnet, ChainId.xDai, ChainId.Matic, ChainId.Rinkeby], }, }, } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx index 2b7cb048d53b..9446de0228e9 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx @@ -1,16 +1,17 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { useEffect } from 'react' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' export interface PluginNetworkWatcherProps { - network?: Plugin.Shared.Network + network?: Web3Plugin.NetworkDescriptor expectedPluginID: string expectedNetworkID: string } export function PluginNetworkWatcher({ network, expectedPluginID, expectedNetworkID }: PluginNetworkWatcherProps) { useEffect(() => { - const matched = network && network.pluginID === expectedPluginID && network.ID === expectedNetworkID + const matched = + network && network.networkSupporterPluginID === expectedPluginID && network.ID === expectedNetworkID if (!matched) return pluginIDSettings.value = expectedPluginID networkIDSettings.value = expectedNetworkID diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index bc47b3d37a8b..b5c6b723fc45 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -1,6 +1,6 @@ import { SuccessIcon } from '@masknet/icons' import { ImageIcon } from '@masknet/shared' -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { getMaskColor, makeStyles } from '@masknet/theme' import { Box, ImageList, ImageListItem, List, ListItem, Typography } from '@mui/material' import { ProviderIcon } from './ProviderIcon' @@ -67,16 +67,19 @@ const useStyles = makeStyles()((theme) => ({ })) export interface PluginProviderRenderProps { - networks: Plugin.Shared.Network[] - providers: Plugin.Shared.Provider[] + networks: Web3Plugin.NetworkDescriptor[] + providers: Web3Plugin.ProviderDescriptor[] undeterminedPluginID: string undeterminedNetworkID: string setUndeterminedPluginID: (id: string) => void setUndeterminedNetworkID: (id: string) => void - NetworkIconClickBait?: React.ComponentType<{ network: Plugin.Shared.Network; children?: React.ReactNode }> + NetworkIconClickBait?: React.ComponentType<{ + network: Web3Plugin.NetworkDescriptor + children?: React.ReactNode + }> ProviderIconClickBait?: React.ComponentType<{ - network: Plugin.Shared.Network - provider: Plugin.Shared.Provider + network: Web3Plugin.NetworkDescriptor + provider: Web3Plugin.ProviderDescriptor children?: React.ReactNode }> onSubmit: () => void @@ -108,16 +111,16 @@ export function PluginProviderRender({ className={classes.networkItem} key={network.ID} onClick={() => { - setUndeterminedPluginID(network.pluginID) + setUndeterminedPluginID(network.networkSupporterPluginID) setUndeterminedNetworkID(network.ID) }}>
    {NetworkIconClickBait ? ( - + ) : ( - + )} {undeterminedNetworkID === network.ID && ( @@ -133,17 +136,17 @@ export function PluginProviderRender({ {providers - .filter((x) => x.pluginID === undeterminedPluginID) + .filter((x) => x.providerAdaptorPluginID === undeterminedPluginID) .map((provider) => ( {ProviderIconClickBait ? ( x.ID === undeterminedNetworkID)!} provider={provider}> - + ) : ( - + )} ))} diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 81ff75277657..22fe6e4cbe9b 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -1,8 +1,7 @@ import React, { createContext, useContext } from 'react' import { createContainer } from 'unstated-next' import { useSubscription } from 'use-subscription' -import type { Plugin } from '..' -import { CurrencyType, NetworkPluginID } from '../types' +import { CurrencyType, NetworkPluginID, Web3Plugin } from '../web3-types' import { createConstantSubscription } from '../utils' // constant subscriptions @@ -16,7 +15,7 @@ const NULL = createConstantSubscription(null) const PluginIDContext = createContext(NetworkPluginID.PLUGIN_EVM) -const PluginsWeb3Context = createContext>(null!) +const PluginsWeb3Context = createContext>(null!) function usePluginsWeb3Context() { const context = useContext(PluginsWeb3Context) @@ -24,7 +23,7 @@ function usePluginsWeb3Context() { return context } -function usePluginWeb3State(pluginID: string, context: Record) { +function usePluginWeb3State(pluginID: string, context: Record) { const pluginContext = context[pluginID] if (!pluginContext) throw new Error(`The context of ${pluginID} is undefined.`) @@ -93,7 +92,7 @@ export function PluginsWeb3ContextProvider({ pluginID, value, children, -}: { pluginID: string } & React.ProviderProps>) { +}: { pluginID: string } & React.ProviderProps>) { return ( diff --git a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts index 10e96f85821b..ee8c11e5ac02 100644 --- a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts +++ b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts @@ -1,9 +1,9 @@ -import { Plugin, useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor } from '..' +import { useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor, Web3Plugin } from '..' export function useAllPluginsWeb3State() { const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() const pluginsDashboard = useActivatedPluginsDashboard() - return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce>( + return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce>( (accumulator, current) => { if (current.Web3State) { accumulator[current.ID] = current.Web3State diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts index ec454d3cc859..363ee23c138e 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts @@ -1,5 +1,7 @@ import { useRegisteredPlugin } from '.' export function useRegisteredPluginNetwork(pluginID: string, networkTypeOrID?: string) { - return useRegisteredPlugin(pluginID)?.networks?.find((x) => x.type === networkTypeOrID || x.ID === networkTypeOrID) + return useRegisteredPlugin(pluginID)?.declareWeb3Networks?.find( + (x) => x.type === networkTypeOrID || x.ID === networkTypeOrID, + ) } diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts index e2b5699b4f6c..8dc8c3c77f1b 100644 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts +++ b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts @@ -1,7 +1,7 @@ import { useRegisteredPlugin } from '.' export function useRegisteredPluginProvider(pluginID: string, providerTypeOrID?: string) { - return useRegisteredPlugin(pluginID)?.providers?.find( + return useRegisteredPlugin(pluginID)?.declareWeb3Providers?.find( (x) => x.ID === providerTypeOrID || x.type === providerTypeOrID, ) } diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 4388e9792149..7fe9e125a858 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -1,6 +1,7 @@ export * from './web3' export * from './context' export * from './types' +export * from './web3-types' export * from './hooks' export * from './manager/dashboard' export * from './manager/sns-adaptor' diff --git a/packages/plugin-infra/src/manager/sns-adaptor.ts b/packages/plugin-infra/src/manager/sns-adaptor.ts index 89e87b748d2b..ba41bbdde325 100644 --- a/packages/plugin-infra/src/manager/sns-adaptor.ts +++ b/packages/plugin-infra/src/manager/sns-adaptor.ts @@ -22,7 +22,7 @@ export function useActivatedPluginSNSAdaptor(pluginID: string) { export function useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId: number) { const plugins = useActivatedPluginsSNSAdaptor() return plugins.reduce>((acc, cur) => { - const operatingSupportedChains = cur.enableRequirement.web3?.operatingSupportedChains + const operatingSupportedChains = cur.enableRequirement.web3?.supportedOperationalChains acc[cur.ID] = !Boolean(operatingSupportedChains) || Boolean(operatingSupportedChains?.includes(chainId)) return acc }, {}) diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index 3b5c7163909c..4907b1ed510b 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -26,12 +26,12 @@ export function useRegisteredPlugins() { export function useRegisteredNetworks() { const plugins = useRegisteredPlugins() - return useMemo(() => plugins.flatMap((x) => x.networks ?? []), [plugins.map((x) => x.ID).join()]) + return useMemo(() => plugins.flatMap((x) => x.declareWeb3Networks ?? []), [plugins.map((x) => x.ID).join()]) } export function useRegisteredProviders() { const plugins = useRegisteredPlugins() - return useMemo(() => plugins.flatMap((x) => x.providers ?? []), [plugins.map((x) => x.ID).join()]) + return useMemo(() => plugins.flatMap((x) => x.declareWeb3Providers ?? []), [plugins.map((x) => x.ID).join()]) } function __meetRegisterRequirement(def: Plugin.Shared.Definition) { diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 8569596e4062..e9b68a0d22fc 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -2,9 +2,9 @@ import type React from 'react' import type { Option, Result } from 'ts-results' import type { TypedMessage, TypedMessageTuple } from '@masknet/shared' import type { Emitter } from '@servie/events' -import type { Subscription } from 'use-subscription' +import type { Web3Plugin } from './web3-types' -export namespace Plugin { +export declare namespace Plugin { /** * A code loader interface of the plugin API. * @@ -97,9 +97,9 @@ export namespace Plugin.Shared { /** i18n resources of this plugin */ i18n?: I18NResource /** Introduce networks information. */ - networks?: Network[] + declareWeb3Networks?: Web3Plugin.NetworkDescriptor[] /** Introduce wallet providers information. */ - providers?: Provider[] + declareWeb3Providers?: Web3Plugin.ProviderDescriptor[] } /** * This part is shared between Dashboard, SNSAdaptor and Worker part @@ -140,13 +140,8 @@ export namespace Plugin.Shared { architecture: Record<'app' | 'web', boolean> /** The SNS Network this plugin supports. */ networks: SupportedNetworksDeclare - web3?: Web3EnableRequirement - } - export interface Web3EnableRequirement { - /** Plugin can declare what chain it supports. When the current chain is not supported, the composition entry will be hidden. */ - operatingSupportedChains?: number[] + web3?: Web3Plugin.EnableRequirement } - export interface ManagementProperty { /** This plugin should not displayed in the plugin management page. */ internal?: boolean @@ -171,245 +166,6 @@ export namespace Plugin.Shared { export type I18NKey = string export type I18NValue = string export type I18NResource = Record> - - export interface Network { - /** An unique ID for each network */ - ID: string - /** The plugin ID */ - pluginID: string - /** The network type */ - type: string - /** The network icon */ - icon: string - /** The network name */ - name: string - } - - export interface Provider { - /** An unique ID for each wallet provider */ - ID: string - /** The plugin ID */ - pluginID: string - /** The provider type */ - type: string - /** The provider icon */ - icon: string - /** The provider name */ - name: string - } - - export interface Web3UI { - SelectProviderDialog?: { - /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ - NetworkIconClickBait?: React.ComponentType<{ network: Shared.Network; children?: React.ReactNode }> - /** This UI will receive provider icon as children component, and the plugin may hook click handle on it. */ - ProviderIconClickBait?: React.ComponentType<{ - network: Shared.Network - provider: Shared.Provider - children?: React.ReactNode - }> - } - Dashboard?: { - OverviewComponent?: React.ComponentType<{}> - AssetsTableComponent?: React.ComponentType<{}> - TransferTableComponent?: React.ComponentType<{}> - HistoryTableComponent?: React.ComponentType<{}> - } - } - - export interface CryptoPrice { - [token: string]: { - [key in CurrencyType]: number - } - } - - export interface ChainDetailed { - name: string - chainId: number - fullName: string - shortName: string - chainName: string - networkName: string - } - - export interface Wallet { - /** User define wallet name. Default address.prefix(6) */ - name: string - /** The address of wallet */ - address: string - /** yep: Mask Wallet, nope: External Wallet */ - hasStoredKeyInfo: boolean - /** yep: Derivable Wallet. nope: UnDerivable Wallet */ - hasDerivationPath: boolean - } - - export interface Pagination { - /** The item size of each page. */ - size?: number - /** The page index. */ - page?: number - } - - export interface Asset { - id: string - chain: string - balance: string - token: Token - /** estimated price */ - price?: { - [key in CurrencyType]: string - } - /** estimated value */ - value?: { - [key in CurrencyType]: string - } - logoURI?: string - } - - export interface AddressName { - id: string - /** eg. vitalik.eth */ - label: string - /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ - ownerAddress: string - /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ - resolvedAddress?: string - } - - export interface Transaction { - id: string - type: string - title: string - from: string - to: string - timestamp: string - /** 0: failed 1: succeed */ - status: 0 | 1 - /** estimated tx fee */ - fee: { - [key in CurrencyType]: string - } - } - - export interface Token { - id: string - type: TokenType - token: T - } - - export interface FungibleTokenMetadata { - name: string - symbol: string - decimals: number - iconURL?: string - _token: T - } - - export interface NonFungibleTokenMetadata { - name: string - description: string - mediaType: string - iconURL?: string - assetURL?: string - _token: T - } - - export interface TokenList { - name: string - description?: string - tokens: Token[] - } - - export interface Web3State { - Shared?: { - allowTestnet?: Subscription - /** The ID of currently chosen sub-network. */ - chainId?: Subscription - /** The address of the currently chosen wallet. */ - account?: Subscription - /** The balance of the currently chosen account. */ - balance?: Subscription - /** The currently tracked block height. */ - blockNumber?: Subscription - /** The network type. */ - networkType?: Subscription - /** The wallet provider type. */ - providerType?: Subscription - /** The asset data provider. */ - assetType?: Subscription - /** The address name data provider. */ - nameType?: Subscription - /** The collectible data provider. */ - collectibleType?: Subscription - /** The transaction data provider. */ - transactionType?: Subscription - /** The currency of estimated values and prices. */ - currencyType?: Subscription - /** The tracked token prices which stored as address and price pairs. */ - prices?: Subscription - /** The currently stored wallet by MaskWallet. */ - wallets?: Subscription - /** The default derivable wallet. */ - walletPrimary?: Subscription - /** The user added fungible tokens. */ - fungibleTokens?: Subscription[]> - /** The user added non-fungible tokens. */ - nonFungibleTokens?: Subscription[]> - } - Asset?: { - /** Get fungible assets of given account. */ - getFungibleAssets?: ( - address: string, - providerType: string, - networkType: string, - pagination?: Pagination, - ) => Promise[]> - /** Get non-fungible assets of given account. */ - getNonFungibleAssets: ( - address: string, - providerType: string, - networkType: string, - pagination?: Pagination, - ) => Promise[]> - } - Token?: { - addToken: (token: Token) => Promise - removeToken: (token: Token) => Promise - trustToken: (token: Token) => Promise - blockToken: (token: Token) => Promise - } - Transaction?: { - /** Get latest transactions of given account. */ - getTransactions: ( - address: string, - providerType: string, - networkType: string, - pagination?: Pagination, - ) => Promise - } - TokenList?: { - /** Get the token lists of supported fungible tokens. */ - getFungibleTokenLists: ( - address: string, - providerType: string, - networkType: string, - pagination?: Pagination, - ) => Promise[]> - /** Get the token lists of supported non-fungible tokens. */ - getNonFungibleTokenLists: ( - address: string, - providerType: string, - networkType: string, - pagination?: Pagination, - ) => Promise[]> - } - Utils?: { - isChainIdValid: (chainId: number, allowTestnet: boolean) => boolean - getChainDetailed: (chainId: number) => ChainDetailed - getFungibleTokenMetadata: (token: Token) => Promise> - getNonFungibleTokenMetadata: (token: Token) => Promise> - } - } } /** This part runs in the SNSAdaptor */ @@ -424,9 +180,9 @@ export namespace Plugin.SNSAdaptor { /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UI?: Shared.Web3UI + Web3UI?: Web3Plugin.Web3UI /** This is the context of the currently chosen network. */ - Web3State?: Shared.Web3State + Web3State?: Web3Plugin.Web3State /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -518,9 +274,9 @@ export namespace Plugin.Dashboard { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UI?: Shared.Web3UI + Web3UI?: Web3Plugin.Web3UI /** This is the context of the currently chosen network. */ - Web3State?: Shared.Web3State + Web3State?: Web3Plugin.Web3State } } @@ -668,7 +424,6 @@ export type IndexableTaggedUnion = { type: string | number id: string | number } -// TODO: Plugin i18n is not read today. export interface I18NStringField { /** The i18n key of the string content. */ i18nKey?: string @@ -687,25 +442,12 @@ export enum CurrentSNSNetwork { Instagram = 3, } -/** - * A network plugin defines the way to connect to a single chain. - */ -export enum NetworkPluginID { - PLUGIN_EVM = 'com.maskbook.evm', - PLUGIN_FLOW = 'com.maskbook.flow', -} - -export enum CurrencyType { - NATIVE = 'native', - BTC = 'btc', - USD = 'usd', +export interface Pagination { + /** The item size of each page. */ + size?: number + /** The page index. */ + page?: number } - -export enum TokenType { - Fungible = 'Fungible', - NonFungible = 'NonFungible', -} - /** * This namespace is not related to the plugin authors */ diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts new file mode 100644 index 000000000000..4a3bf948f944 --- /dev/null +++ b/packages/plugin-infra/src/web3-types.ts @@ -0,0 +1,258 @@ +import type { Subscription } from 'use-subscription' +import type { Pagination } from './types' +export declare namespace Web3Plugin { + export interface EnableRequirement { + /** + * Plugin can declare what chain it supports to trigger side effects (e.g. create a new transaction). + * When the current chain is not supported, the composition entry will be hidden. + */ + supportedOperationalChains?: number[] + } + export interface NetworkDescriptor { + /** An unique ID for each network */ + ID: string + /** The ID of a plugin that provides the functionality of this network. */ + networkSupporterPluginID: string + /** The network type */ + type: string + /** The network icon */ + icon: URL + /** The network name */ + name: string + } + export interface ProviderDescriptor { + /** An unique ID for each wallet provider */ + ID: string + /** The ID of a plugin that provides the adoption of this provider. */ + providerAdaptorPluginID: string + /** The provider type */ + type: string + /** The provider icon */ + icon: URL + /** The provider name */ + name: string + } + export interface CryptoPrice { + [token: string]: { + [key in CurrencyType]: number + } + } + export interface ChainDetailed { + name: string + chainId: number + fullName: string + shortName: string + chainName: string + networkName: string + } + export interface Wallet { + /** User define wallet name. Default address.prefix(6) */ + name: string + /** The address of wallet */ + address: string + /** true: Mask Wallet, false: External Wallet */ + hasStoredKeyInfo: boolean + /** true: Derivable Wallet. false: UnDerivable Wallet */ + hasDerivationPath: boolean + } + export interface Asset { + id: string + chain: string + balance: string + token: Token + /** estimated price */ + price?: { + [key in CurrencyType]: string + } + /** estimated value */ + value?: { + [key in CurrencyType]: string + } + logoURI?: string + } + + export interface AddressName { + id: string + /** eg. vitalik.eth */ + label: string + /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ + ownerAddress: string + /** eg. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 */ + resolvedAddress?: string + } + + export interface Transaction { + id: string + type: string + title: string + from: string + to: string + timestamp: string + /** 0: failed 1: succeed */ + status: 0 | 1 + /** estimated tx fee */ + fee: { + [key in CurrencyType]: string + } + } + + export interface Token { + id: string + type: TokenType + token: T + } + + export interface FungibleTokenMetadata { + name: string + symbol: string + decimals: number + iconURL?: string + _token: T + } + + export interface NonFungibleTokenMetadata { + name: string + description: string + mediaType: string + iconURL?: string + assetURL?: string + _token: T + } + + export interface TokenList { + name: string + description?: string + tokens: Token[] + } + export interface Web3State { + Shared?: { + allowTestnet?: Subscription + /** The ID of currently chosen sub-network. */ + chainId?: Subscription + /** The address of the currently chosen wallet. */ + account?: Subscription + /** The balance of the currently chosen account. */ + balance?: Subscription + /** The currently tracked block height. */ + blockNumber?: Subscription + /** The network type. */ + networkType?: Subscription + /** The wallet provider type. */ + providerType?: Subscription + /** The asset data provider. */ + assetType?: Subscription + /** The address name data provider. */ + nameType?: Subscription + /** The collectible data provider. */ + collectibleType?: Subscription + /** The transaction data provider. */ + transactionType?: Subscription + /** The currency of estimated values and prices. */ + currencyType?: Subscription + /** The tracked token prices which stored as address and price pairs. */ + prices?: Subscription + /** The currently stored wallet by MaskWallet. */ + wallets?: Subscription + /** The default derivable wallet. */ + walletPrimary?: Subscription + /** The user added fungible tokens. */ + fungibleTokens?: Subscription[]> + /** The user added non-fungible tokens. */ + nonFungibleTokens?: Subscription[]> + } + Asset?: { + /** Get fungible assets of given account. */ + getFungibleAssets?: ( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ) => Promise[]> + /** Get non-fungible assets of given account. */ + getNonFungibleAssets: ( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ) => Promise[]> + } + Token?: { + addToken: (token: Token) => Promise + removeToken: (token: Token) => Promise + trustToken: (token: Token) => Promise + blockToken: (token: Token) => Promise + } + Transaction?: { + /** Get latest transactions of given account. */ + getTransactions: ( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ) => Promise + } + TokenList?: { + /** Get the token lists of supported fungible tokens. */ + getFungibleTokenLists: ( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ) => Promise[]> + /** Get the token lists of supported non-fungible tokens. */ + getNonFungibleTokenLists: ( + address: string, + providerType: string, + networkType: string, + pagination?: Pagination, + ) => Promise[]> + } + Utils?: { + isChainIdValid: (chainId: number, allowTestnet: boolean) => boolean + getChainDetailed: (chainId: number) => ChainDetailed + getFungibleTokenMetadata: (token: Token) => Promise> + getNonFungibleTokenMetadata: (token: Token) => Promise> + } + } + + export interface Web3UI { + SelectProviderDialog?: { + /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ + NetworkIconClickBait?: React.ComponentType<{ + network: NetworkDescriptor + children?: React.ReactNode + }> + /** This UI will receive provider icon as children component, and the plugin may hook click handle on it. */ + ProviderIconClickBait?: React.ComponentType<{ + network: NetworkDescriptor + provider: ProviderDescriptor + children?: React.ReactNode + }> + } + Dashboard?: { + OverviewComponent?: React.ComponentType<{}> + AssetsTableComponent?: React.ComponentType<{}> + TransferTableComponent?: React.ComponentType<{}> + HistoryTableComponent?: React.ComponentType<{}> + } + } +} + +/** + * A network plugin defines the way to connect to a single chain. + */ +export enum NetworkPluginID { + PLUGIN_EVM = 'com.maskbook.evm', + PLUGIN_FLOW = 'com.maskbook.flow', +} + +export enum CurrencyType { + NATIVE = 'native', + BTC = 'btc', + USD = 'usd', +} + +export enum TokenType { + Fungible = 'Fungible', + NonFungible = 'NonFungible', +} diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts index b123fd23275d..836cea0da45a 100644 --- a/packages/plugin-infra/src/web3/useTokenPrice.ts +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -1,4 +1,4 @@ -import type { CurrencyType } from '../types' +import type { CurrencyType } from '../web3-types' import { usePluginWeb3StateContext } from '../context' export function useTokenPrice(id: string, currencyType: string, pluginID?: string) { diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index 4338893b3458..e51dac488a54 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -1,6 +1,6 @@ import { remove } from 'lodash-es' import * as fcl from '@onflow/fcl' -import { createConstantSubscription, createSubscriptionFromAsync, Plugin } from '@masknet/plugin-infra' +import { createConstantSubscription, createSubscriptionFromAsync, Web3Plugin } from '@masknet/plugin-infra' import { getAuthConstants } from '@masknet/web3-shared-flow/constants' import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-flow' @@ -50,4 +50,4 @@ function createWeb3State() { } } -export const Web3State: Plugin.Shared.Web3State = createWeb3State() +export const Web3State: Web3Plugin.Web3State = createWeb3State() diff --git a/packages/plugins/Flow/src/UI/Web3UI/index.tsx b/packages/plugins/Flow/src/UI/Web3UI/index.tsx index 4982f2d52a6b..b8ed3c6fa77e 100644 --- a/packages/plugins/Flow/src/UI/Web3UI/index.tsx +++ b/packages/plugins/Flow/src/UI/Web3UI/index.tsx @@ -1,7 +1,7 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UI: Plugin.Shared.Web3UI = { +export const Web3UI: Web3Plugin.Web3UI = { SelectProviderDialog: { ProviderIconClickBait, }, diff --git a/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx index 2351ccf4e2ef..5b5656e398db 100644 --- a/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx +++ b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx @@ -1,10 +1,10 @@ import { useCallback, cloneElement, isValidElement } from 'react' -import type { Plugin } from '@masknet/plugin-infra/src' +import type { Web3Plugin } from '@masknet/plugin-infra' import { NetworkType, ProviderType, useFCL } from '@masknet/web3-shared-flow' export interface ProviderIconClickBaitProps { - network: Plugin.Shared.Network - provider: Plugin.Shared.Provider + network: Web3Plugin.NetworkDescriptor + provider: Web3Plugin.ProviderDescriptor children?: React.ReactNode } diff --git a/packages/plugins/Flow/src/base.ts b/packages/plugins/Flow/src/base.ts index 858a80402717..c83965435f85 100644 --- a/packages/plugins/Flow/src/base.ts +++ b/packages/plugins/Flow/src/base.ts @@ -14,6 +14,6 @@ export const base: Plugin.Shared.Definition = { target: 'stable', }, i18n: languages, - networks: PLUGIN_NETWORKS, - providers: PLUGIN_PROVIDERS, + declareWeb3Networks: PLUGIN_NETWORKS, + declareWeb3Providers: PLUGIN_PROVIDERS, } diff --git a/packages/plugins/Flow/src/constants.ts b/packages/plugins/Flow/src/constants.ts index 31c3ed9b430c..d3dc5309a591 100644 --- a/packages/plugins/Flow/src/constants.ts +++ b/packages/plugins/Flow/src/constants.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { NetworkType, ProviderType } from '@masknet/web3-shared-flow/types' export const PLUGIN_META_KEY = 'com.maskbook.flow' @@ -6,21 +6,21 @@ export const PLUGIN_ID = 'com.maskbook.flow' export const PLUGIN_NAME = 'Flow Chain' export const PLUGIN_ICON = 'F' export const PLUGIN_DESCRIPTION = '' -export const PLUGIN_NETWORKS: Plugin.Shared.Network[] = [ +export const PLUGIN_NETWORKS: Web3Plugin.NetworkDescriptor[] = [ { ID: `${PLUGIN_ID}_flow`, - pluginID: PLUGIN_ID, + networkSupporterPluginID: PLUGIN_ID, type: NetworkType.Flow, name: 'Flow', - icon: new URL('./assets/flow.png', import.meta.url).toString(), + icon: new URL('./assets/flow.png', import.meta.url), }, ] -export const PLUGIN_PROVIDERS: Plugin.Shared.Provider[] = [ +export const PLUGIN_PROVIDERS: Web3Plugin.ProviderDescriptor[] = [ { ID: `${PLUGIN_ID}_blocto`, - pluginID: PLUGIN_ID, + providerAdaptorPluginID: PLUGIN_ID, type: ProviderType.Blocto, name: 'Blocto', - icon: new URL('./assets/blocto.png', import.meta.url).toString(), + icon: new URL('./assets/blocto.png', import.meta.url), }, ] From 7b59c9099877ce33f6569371fdf21e173ac10d1a Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 14:34:44 +0800 Subject: [PATCH 25/41] refactor: rename some types --- .../src/plugins/EVM/UI/Web3State/index.ts | 4 +- .../mask/src/plugins/EVM/UI/Web3UI/index.tsx | 2 +- .../PluginProviderRender.tsx | 11 +--- packages/plugin-infra/src/context/index.tsx | 6 +- .../src/hooks/useAllPluginsWeb3State.ts | 17 +++--- packages/plugin-infra/src/types.ts | 8 +-- packages/plugin-infra/src/web3-types.ts | 56 +++++++++++-------- .../plugins/Flow/src/UI/Web3State/index.ts | 2 +- packages/plugins/Flow/src/UI/Web3UI/index.tsx | 2 +- 9 files changed, 54 insertions(+), 54 deletions(-) diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index 54958b1aa956..d026f283db2f 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,9 +1,9 @@ import type { Web3Plugin } from '@masknet/plugin-infra' import type { Web3ProviderType } from '@masknet/web3-shared-evm' -export const Web3State: Web3Plugin.Web3State = {} +export const Web3State: Web3Plugin.ObjectCapabilities.Capabilities = {} -export function fixWeb3State(state?: Web3Plugin.Web3State, context?: Web3ProviderType) { +export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, context?: Web3ProviderType) { if (!state || !context) return state.Shared = state.Shared ?? { allowTestnet: context.allowTestnet, diff --git a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx index b8ed3c6fa77e..017a04ffe144 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx +++ b/packages/mask/src/plugins/EVM/UI/Web3UI/index.tsx @@ -1,7 +1,7 @@ import type { Web3Plugin } from '@masknet/plugin-infra' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UI: Web3Plugin.Web3UI = { +export const Web3UI: Web3Plugin.UI.UI = { SelectProviderDialog: { ProviderIconClickBait, }, diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index b5c6b723fc45..f7970a0fe9cd 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -73,15 +73,8 @@ export interface PluginProviderRenderProps { undeterminedNetworkID: string setUndeterminedPluginID: (id: string) => void setUndeterminedNetworkID: (id: string) => void - NetworkIconClickBait?: React.ComponentType<{ - network: Web3Plugin.NetworkDescriptor - children?: React.ReactNode - }> - ProviderIconClickBait?: React.ComponentType<{ - network: Web3Plugin.NetworkDescriptor - provider: Web3Plugin.ProviderDescriptor - children?: React.ReactNode - }> + NetworkIconClickBait?: React.ComponentType + ProviderIconClickBait?: React.ComponentType onSubmit: () => void } diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 22fe6e4cbe9b..1e9bcab29202 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -15,7 +15,7 @@ const NULL = createConstantSubscription(null) const PluginIDContext = createContext(NetworkPluginID.PLUGIN_EVM) -const PluginsWeb3Context = createContext>(null!) +const PluginsWeb3Context = createContext>(null!) function usePluginsWeb3Context() { const context = useContext(PluginsWeb3Context) @@ -23,7 +23,7 @@ function usePluginsWeb3Context() { return context } -function usePluginWeb3State(pluginID: string, context: Record) { +function usePluginWeb3State(pluginID: string, context: Record) { const pluginContext = context[pluginID] if (!pluginContext) throw new Error(`The context of ${pluginID} is undefined.`) @@ -92,7 +92,7 @@ export function PluginsWeb3ContextProvider({ pluginID, value, children, -}: { pluginID: string } & React.ProviderProps>) { +}: { pluginID: string } & React.ProviderProps>) { return ( diff --git a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts index ee8c11e5ac02..27460fb279da 100644 --- a/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts +++ b/packages/plugin-infra/src/hooks/useAllPluginsWeb3State.ts @@ -3,13 +3,12 @@ import { useActivatedPluginsDashboard, useActivatedPluginsSNSAdaptor, Web3Plugin export function useAllPluginsWeb3State() { const pluginsSNSAdaptor = useActivatedPluginsSNSAdaptor() const pluginsDashboard = useActivatedPluginsDashboard() - return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce>( - (accumulator, current) => { - if (current.Web3State) { - accumulator[current.ID] = current.Web3State - } - return accumulator - }, - {}, - ) + type T = Record + + return [...pluginsSNSAdaptor, ...pluginsDashboard].reduce((accumulator, current) => { + if (current.Web3State) { + accumulator[current.ID] = current.Web3State + } + return accumulator + }, {}) } diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index e9b68a0d22fc..b1266b95d170 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -180,9 +180,9 @@ export namespace Plugin.SNSAdaptor { /** This UI will be rendered into the global scope of an SNS. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UI?: Web3Plugin.Web3UI + Web3UI?: Web3Plugin.UI.UI /** This is the context of the currently chosen network. */ - Web3State?: Web3Plugin.Web3State + Web3State?: Web3Plugin.ObjectCapabilities.Capabilities /** This UI will be an entry to the plugin in the Composition dialog of Mask. */ CompositionDialogEntry?: CompositionDialogEntry /** This UI will be use when there is known badges. */ @@ -274,9 +274,9 @@ export namespace Plugin.Dashboard { /** This UI will be injected into the global scope of the Dashboard. */ GlobalInjection?: InjectUI<{}> /** This is a chunk of web3 UIs to be rendered into various places of Mask UI. */ - Web3UI?: Web3Plugin.Web3UI + Web3UI?: Web3Plugin.UI.UI /** This is the context of the currently chosen network. */ - Web3State?: Web3Plugin.Web3State + Web3State?: Web3Plugin.ObjectCapabilities.Capabilities } } diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 4a3bf948f944..f6976ea0293e 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -1,5 +1,7 @@ import type { Subscription } from 'use-subscription' import type { Pagination } from './types' +import type { Plugin } from '.' + export declare namespace Web3Plugin { export interface EnableRequirement { /** @@ -124,8 +126,8 @@ export declare namespace Web3Plugin { description?: string tokens: Token[] } - export interface Web3State { - Shared?: { + export namespace ObjectCapabilities { + export interface SharedState { allowTestnet?: Subscription /** The ID of currently chosen sub-network. */ chainId?: Subscription @@ -160,7 +162,7 @@ export declare namespace Web3Plugin { /** The user added non-fungible tokens. */ nonFungibleTokens?: Subscription[]> } - Asset?: { + export interface AssetState { /** Get fungible assets of given account. */ getFungibleAssets?: ( address: string, @@ -176,13 +178,13 @@ export declare namespace Web3Plugin { pagination?: Pagination, ) => Promise[]> } - Token?: { + export interface TokenManage { addToken: (token: Token) => Promise removeToken: (token: Token) => Promise trustToken: (token: Token) => Promise blockToken: (token: Token) => Promise } - Transaction?: { + export interface TransactionState { /** Get latest transactions of given account. */ getTransactions: ( address: string, @@ -191,7 +193,7 @@ export declare namespace Web3Plugin { pagination?: Pagination, ) => Promise } - TokenList?: { + export interface TokenListState { /** Get the token lists of supported fungible tokens. */ getFungibleTokenLists: ( address: string, @@ -207,33 +209,39 @@ export declare namespace Web3Plugin { pagination?: Pagination, ) => Promise[]> } - Utils?: { + export interface Others { isChainIdValid: (chainId: number, allowTestnet: boolean) => boolean getChainDetailed: (chainId: number) => ChainDetailed getFungibleTokenMetadata: (token: Token) => Promise> getNonFungibleTokenMetadata: (token: Token) => Promise> } + export interface Capabilities { + Shared?: SharedState + Asset?: AssetState + Token?: TokenManage + Transaction?: TransactionState + TokenList?: TokenListState + Utils?: Others + } } - - export interface Web3UI { - SelectProviderDialog?: { + export namespace UI { + export interface NetworkIconClickBaitProps { + network: NetworkDescriptor + children?: React.ReactNode + } + export interface ProviderIconClickBaitProps { + network: NetworkDescriptor + provider: ProviderDescriptor + children?: React.ReactNode + } + export interface SelectProviderDialogBait { /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ - NetworkIconClickBait?: React.ComponentType<{ - network: NetworkDescriptor - children?: React.ReactNode - }> + NetworkIconClickBait?: Plugin.InjectUIReact /** This UI will receive provider icon as children component, and the plugin may hook click handle on it. */ - ProviderIconClickBait?: React.ComponentType<{ - network: NetworkDescriptor - provider: ProviderDescriptor - children?: React.ReactNode - }> + ProviderIconClickBait?: Plugin.InjectUIReact } - Dashboard?: { - OverviewComponent?: React.ComponentType<{}> - AssetsTableComponent?: React.ComponentType<{}> - TransferTableComponent?: React.ComponentType<{}> - HistoryTableComponent?: React.ComponentType<{}> + export interface UI { + SelectProviderDialog?: SelectProviderDialogBait } } } diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index e51dac488a54..1806befc4427 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -50,4 +50,4 @@ function createWeb3State() { } } -export const Web3State: Web3Plugin.Web3State = createWeb3State() +export const Web3State: Web3Plugin.ObjectCapabilities.Capabilities = createWeb3State() diff --git a/packages/plugins/Flow/src/UI/Web3UI/index.tsx b/packages/plugins/Flow/src/UI/Web3UI/index.tsx index b8ed3c6fa77e..017a04ffe144 100644 --- a/packages/plugins/Flow/src/UI/Web3UI/index.tsx +++ b/packages/plugins/Flow/src/UI/Web3UI/index.tsx @@ -1,7 +1,7 @@ import type { Web3Plugin } from '@masknet/plugin-infra' import { ProviderIconClickBait } from '../components/ProviderIconClickBait' -export const Web3UI: Web3Plugin.Web3UI = { +export const Web3UI: Web3Plugin.UI.UI = { SelectProviderDialog: { ProviderIconClickBait, }, From 7527e9e9a233eb393b266190327d864588721461 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 14:44:50 +0800 Subject: [PATCH 26/41] refactor: move some files --- packages/plugin-infra/src/context/index.tsx | 2 +- packages/plugin-infra/src/utils/index.ts | 1 - packages/plugins/Flow/src/UI/Web3State/index.ts | 3 ++- packages/shared-base/src/utils/index.ts | 1 + .../src/utils/subscription.ts | 7 ------- 5 files changed, 4 insertions(+), 10 deletions(-) rename packages/{plugin-infra => shared-base}/src/utils/subscription.ts (91%) diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/context/index.tsx index 1e9bcab29202..d23b53691f24 100644 --- a/packages/plugin-infra/src/context/index.tsx +++ b/packages/plugin-infra/src/context/index.tsx @@ -2,7 +2,7 @@ import React, { createContext, useContext } from 'react' import { createContainer } from 'unstated-next' import { useSubscription } from 'use-subscription' import { CurrencyType, NetworkPluginID, Web3Plugin } from '../web3-types' -import { createConstantSubscription } from '../utils' +import { createConstantSubscription } from '@masknet/shared' // constant subscriptions const ZERO = createConstantSubscription(0) diff --git a/packages/plugin-infra/src/utils/index.ts b/packages/plugin-infra/src/utils/index.ts index cfea07dfa23b..091067f16c38 100644 --- a/packages/plugin-infra/src/utils/index.ts +++ b/packages/plugin-infra/src/utils/index.ts @@ -1,4 +1,3 @@ export { createInjectHooksRenderer } from './createInjectHooksRenderer' export * from './message' export * from './rpc' -export * from './subscription' diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index 1806befc4427..037aa4ba731c 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -1,8 +1,9 @@ import { remove } from 'lodash-es' import * as fcl from '@onflow/fcl' -import { createConstantSubscription, createSubscriptionFromAsync, Web3Plugin } from '@masknet/plugin-infra' +import type { Web3Plugin } from '@masknet/plugin-infra' import { getAuthConstants } from '@masknet/web3-shared-flow/constants' import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-flow' +import { createConstantSubscription, createSubscriptionFromAsync } from '@masknet/shared-base' function createClient(chainId: ChainId) { const authConstants = getAuthConstants(chainId) diff --git a/packages/shared-base/src/utils/index.ts b/packages/shared-base/src/utils/index.ts index 195a0389a19b..4661d19f6ac4 100644 --- a/packages/shared-base/src/utils/index.ts +++ b/packages/shared-base/src/utils/index.ts @@ -4,3 +4,4 @@ export * from './timeout' export * from './enum' export * from './pollingTask' export * from './sessionStorageCache' +export * from './subscription' diff --git a/packages/plugin-infra/src/utils/subscription.ts b/packages/shared-base/src/utils/subscription.ts similarity index 91% rename from packages/plugin-infra/src/utils/subscription.ts rename to packages/shared-base/src/utils/subscription.ts index 3d155c4bc9e3..c0be775c3a81 100644 --- a/packages/plugin-infra/src/utils/subscription.ts +++ b/packages/shared-base/src/utils/subscription.ts @@ -1,13 +1,6 @@ import { noop } from 'lodash-es' import type { Subscription } from 'use-subscription' -export function createStaticSubscription(getter: () => T) { - return { - getCurrentValue: getter, - subscribe: () => noop, - } -} - export function createConstantSubscription(value: T) { return { getCurrentValue: () => value, From 3241b9889d573256df1849beb0b4c955f4c45203 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 15:11:52 +0800 Subject: [PATCH 27/41] refactor: remove some usage of hooks --- .../CompositionDialog/PluginEntryRender.tsx | 4 +-- .../InjectedComponents/ToolboxUnstyled.tsx | 4 +-- .../SNSAdaptor/SelectProviderDialog/index.tsx | 12 +++---- packages/plugin-infra/src/hooks/index.ts | 3 -- .../src/hooks/useRegisteredPlugin.ts | 6 ---- .../src/hooks/useRegisteredPluginNetwork.ts | 7 ---- .../src/hooks/useRegisteredPluginProvider.ts | 7 ---- packages/plugin-infra/src/index.ts | 7 ++-- packages/plugin-infra/src/manager/manage.ts | 3 +- .../plugin-infra/src/manager/sns-adaptor.ts | 2 +- packages/plugin-infra/src/manager/store.ts | 35 +++++++++++-------- .../src/web3/getRegisteredPluginNetwork.ts | 7 ++++ .../src/web3/getRegisteredPluginProvider.ts | 6 ++++ packages/plugin-infra/src/web3/index.ts | 2 ++ 14 files changed, 53 insertions(+), 52 deletions(-) delete mode 100644 packages/plugin-infra/src/hooks/useRegisteredPlugin.ts delete mode 100644 packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts delete mode 100644 packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts create mode 100644 packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts create mode 100644 packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts diff --git a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx index b6602a7a00f4..05a4fa29d7f6 100644 --- a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx +++ b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx @@ -1,5 +1,5 @@ import { - useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet, + useActivatedPluginSNSAdaptor_withSupportOperateChain, useActivatedPluginsSNSAdaptor, Plugin, } from '@masknet/plugin-infra' @@ -26,7 +26,7 @@ export const PluginEntryRender = memo( const [trackPluginRef] = useSetPluginEntryRenderRef(ref) const pluginField = usePluginI18NField() const chainId = useChainId() - const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId) + const operatingSupportedChainMapping = useActivatedPluginSNSAdaptor_withSupportOperateChain(chainId) const result = [...useActivatedPluginsSNSAdaptor()] .sort((plugin) => { // TODO: support priority order diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 1c6ba72b3102..7e9293586306 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -23,7 +23,7 @@ import { useChainId, } from '@masknet/web3-shared-evm' import { - useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet, + useActivatedPluginSNSAdaptor_withSupportOperateChain, useActivatedPluginsSNSAdaptor, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' @@ -177,7 +177,7 @@ function useToolbox() { const chainColor = useChainColor() const chainIdValid = useChainIdValid() const chainDetailed = useChainDetailed() - const operatingSupportedChainMapping = useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId) + const operatingSupportedChainMapping = useActivatedPluginSNSAdaptor_withSupportOperateChain(chainId) //#region recent pending transactions const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index cfda21f310ff..61bda0898677 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -10,11 +10,11 @@ import { PluginProviderRender } from './PluginProviderRender' import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' import { - useRegisteredNetworks, - useRegisteredProviders, + getRegisteredWeb3Networks, + getRegisteredWeb3Providers, useActivatedPluginWeb3UI, useNetworkType, - useRegisteredPluginNetwork, + getRegisteredPluginNetwork, } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ @@ -51,10 +51,10 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const undeterminedWeb3UI = useActivatedPluginWeb3UI(undeterminedPluginID) const undeterminedNetworkType = useNetworkType(undeterminedPluginID) - const undeterminedNetwork = useRegisteredPluginNetwork(undeterminedPluginID, undeterminedNetworkType) + const undeterminedNetwork = getRegisteredPluginNetwork(undeterminedPluginID, undeterminedNetworkType) - const networks = useRegisteredNetworks() - const providers = useRegisteredProviders() + const networks = getRegisteredWeb3Networks() + const providers = getRegisteredWeb3Providers() console.log({ pluginID, diff --git a/packages/plugin-infra/src/hooks/index.ts b/packages/plugin-infra/src/hooks/index.ts index 150490d43fb9..a12900325b47 100644 --- a/packages/plugin-infra/src/hooks/index.ts +++ b/packages/plugin-infra/src/hooks/index.ts @@ -2,6 +2,3 @@ export * from './useActivatedPlugin' export * from './useActivatedPluginWeb3UI' export * from './useActivatedPluginWeb3State' export * from './useAllPluginsWeb3State' -export * from './useRegisteredPlugin' -export * from './useRegisteredPluginNetwork' -export * from './useRegisteredPluginProvider' diff --git a/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts b/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts deleted file mode 100644 index c56719b5341b..000000000000 --- a/packages/plugin-infra/src/hooks/useRegisteredPlugin.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useRegisteredPlugins } from '../manager/store' - -export function useRegisteredPlugin(pluginID: string) { - const plugins = useRegisteredPlugins() - return plugins.find((x) => x.ID === pluginID) -} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts deleted file mode 100644 index 363ee23c138e..000000000000 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginNetwork.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useRegisteredPlugin } from '.' - -export function useRegisteredPluginNetwork(pluginID: string, networkTypeOrID?: string) { - return useRegisteredPlugin(pluginID)?.declareWeb3Networks?.find( - (x) => x.type === networkTypeOrID || x.ID === networkTypeOrID, - ) -} diff --git a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts b/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts deleted file mode 100644 index 8dc8c3c77f1b..000000000000 --- a/packages/plugin-infra/src/hooks/useRegisteredPluginProvider.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useRegisteredPlugin } from '.' - -export function useRegisteredPluginProvider(pluginID: string, providerTypeOrID?: string) { - return useRegisteredPlugin(pluginID)?.declareWeb3Providers?.find( - (x) => x.ID === providerTypeOrID || x.type === providerTypeOrID, - ) -} diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 7fe9e125a858..3ddcd180d689 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -10,11 +10,12 @@ export * from './utils' export * from './PostContext' export * from 'ts-results' export { + getPluginDefine, registerPlugin, registeredPlugins, registeredPluginIDs, - useRegisteredPlugins, - useRegisteredNetworks, - useRegisteredProviders, + getRegisteredPluginsSort_EVM_Ahead, + getRegisteredWeb3Networks, + getRegisteredWeb3Providers, } from './manager/store' export { activatedPluginsWorker } from './manager/worker' diff --git a/packages/plugin-infra/src/manager/manage.ts b/packages/plugin-infra/src/manager/manage.ts index 63053c241766..a9b941d8c86a 100644 --- a/packages/plugin-infra/src/manager/manage.ts +++ b/packages/plugin-infra/src/manager/manage.ts @@ -43,9 +43,10 @@ export function createManager, extraCheck?: (id: string) => boolean) { _host = host const { enabled, signal, addI18NResource } = _host + const removeListener = enabled.events.on(ALL_EVENTS, checkRequirementAndStartOrStop) signal?.addEventListener('abort', () => [...activated.keys()].forEach(stopPlugin)) - signal?.addEventListener('abort', enabled.events.on(ALL_EVENTS, checkRequirementAndStartOrStop)) + signal?.addEventListener('abort', removeListener) for (const plugin of registeredPlugins) { plugin.i18n && addI18NResource(plugin.ID, plugin.i18n) diff --git a/packages/plugin-infra/src/manager/sns-adaptor.ts b/packages/plugin-infra/src/manager/sns-adaptor.ts index ba41bbdde325..e7288b5b3f21 100644 --- a/packages/plugin-infra/src/manager/sns-adaptor.ts +++ b/packages/plugin-infra/src/manager/sns-adaptor.ts @@ -19,7 +19,7 @@ export function useActivatedPluginSNSAdaptor(pluginID: string) { return plugins.find((x) => x.ID === pluginID) } -export function useActivatedPluginSNSAdaptorWithOperatingChainSupportedMet(chainId: number) { +export function useActivatedPluginSNSAdaptor_withSupportOperateChain(chainId: number) { const plugins = useActivatedPluginsSNSAdaptor() return plugins.reduce>((acc, cur) => { const operatingSupportedChains = cur.enableRequirement.web3?.supportedOperationalChains diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index 4907b1ed510b..c8f5d8e65144 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -1,5 +1,6 @@ -import { useMemo } from 'react' +// DO NOT import React in this file. This file is also used by worker. import type { Plugin } from '../types' +import { memoize } from 'lodash-es' const __registered = new Map() @@ -14,24 +15,30 @@ export function registerPlugin(def: Plugin.DeferredDefinition) { if (__registered.has(def.ID)) return if (!__meetRegisterRequirement(def)) return __registered.set(def.ID, def) + getRegisteredWeb3Networks_memo.cache.clear?.() + getRegisteredWeb3Providers_memo.cache.clear?.() } -export function useRegisteredPlugins() { - return [...__registered.values()].sort((a, b) => { - if (a.ID.includes('evm')) return -1 - if (b.ID.includes('evm')) return 1 - return 0 - }) +export function getRegisteredPluginsSort_EVM_Ahead() { + return [...__registered.values()].sort(sort_EVM_ahead) } -export function useRegisteredNetworks() { - const plugins = useRegisteredPlugins() - return useMemo(() => plugins.flatMap((x) => x.declareWeb3Networks ?? []), [plugins.map((x) => x.ID).join()]) +function sort_EVM_ahead(a: Plugin.DeferredDefinition, b: Plugin.DeferredDefinition) { + if (a.ID.includes('evm')) return -1 + if (b.ID.includes('evm')) return 1 + return 0 } - -export function useRegisteredProviders() { - const plugins = useRegisteredPlugins() - return useMemo(() => plugins.flatMap((x) => x.declareWeb3Providers ?? []), [plugins.map((x) => x.ID).join()]) +const getRegisteredWeb3Networks_memo = memoize(() => { + return getRegisteredPluginsSort_EVM_Ahead().flatMap((x) => x.declareWeb3Networks || []) +}) +const getRegisteredWeb3Providers_memo = memoize(() => { + return getRegisteredPluginsSort_EVM_Ahead().flatMap((x) => x.declareWeb3Providers || []) +}) +export function getRegisteredWeb3Networks() { + return getRegisteredWeb3Networks_memo() +} +export function getRegisteredWeb3Providers() { + return getRegisteredWeb3Providers_memo() } function __meetRegisterRequirement(def: Plugin.Shared.Definition) { diff --git a/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts b/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts new file mode 100644 index 000000000000..d9f6bf49fd34 --- /dev/null +++ b/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts @@ -0,0 +1,7 @@ +import { getPluginDefine } from '../manager/store' + +export function getRegisteredPluginNetwork(pluginID: string, networkTypeOrID?: string) { + return getPluginDefine(pluginID)?.declareWeb3Networks?.find( + (x) => x.type === networkTypeOrID || x.ID === networkTypeOrID, + ) +} diff --git a/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts b/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts new file mode 100644 index 000000000000..278b83c8772b --- /dev/null +++ b/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts @@ -0,0 +1,6 @@ +import { getPluginDefine } from '../manager/store' +export function getRegisteredPluginProvider(pluginID: string, providerTypeOrID?: string) { + return getPluginDefine(pluginID)?.declareWeb3Providers?.find( + (x) => x.ID === providerTypeOrID || x.type === providerTypeOrID, + ) +} diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts index 670abf6fb00d..8ae5098f51cd 100644 --- a/packages/plugin-infra/src/web3/index.ts +++ b/packages/plugin-infra/src/web3/index.ts @@ -1,3 +1,5 @@ +export * from './getRegisteredPluginNetwork' +export * from './getRegisteredPluginProvider' export * from './useAccount' export * from './useAllowTestnet' export * from './useAssetType' From 5ed997fe7367f161b7736848feeddb21661528c9 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 15:21:45 +0800 Subject: [PATCH 28/41] refactor: move some files --- packages/plugin-infra/src/index.ts | 2 -- packages/plugin-infra/src/manager/store.ts | 2 +- .../plugin-infra/src/{context/index.tsx => web3/Context.tsx} | 0 packages/plugin-infra/src/web3/index.ts | 1 + packages/plugin-infra/src/web3/useAccount.ts | 2 +- packages/plugin-infra/src/web3/useAllowTestnet.ts | 2 +- packages/plugin-infra/src/web3/useAssetType.ts | 2 +- packages/plugin-infra/src/web3/useBalance.ts | 2 +- packages/plugin-infra/src/web3/useBlockNumber.ts | 2 +- packages/plugin-infra/src/web3/useChainDetailed.ts | 2 +- packages/plugin-infra/src/web3/useChainId.ts | 2 +- packages/plugin-infra/src/web3/useCollectibleType.ts | 2 +- packages/plugin-infra/src/web3/useCurrencyType.ts | 2 +- packages/plugin-infra/src/web3/useNameType.ts | 2 +- packages/plugin-infra/src/web3/useNetworkType.ts | 2 +- packages/plugin-infra/src/web3/useProviderType.ts | 2 +- packages/plugin-infra/src/web3/useTokenPrice.ts | 2 +- packages/plugin-infra/src/web3/useTransactionType.ts | 2 +- packages/plugin-infra/src/web3/useWallet.ts | 2 +- packages/plugin-infra/src/web3/useWalletPrimary.ts | 2 +- packages/plugin-infra/src/web3/useWallets.ts | 2 +- 21 files changed, 19 insertions(+), 20 deletions(-) rename packages/plugin-infra/src/{context/index.tsx => web3/Context.tsx} (100%) diff --git a/packages/plugin-infra/src/index.ts b/packages/plugin-infra/src/index.ts index 3ddcd180d689..5e81b48951f4 100644 --- a/packages/plugin-infra/src/index.ts +++ b/packages/plugin-infra/src/index.ts @@ -1,5 +1,4 @@ export * from './web3' -export * from './context' export * from './types' export * from './web3-types' export * from './hooks' @@ -14,7 +13,6 @@ export { registerPlugin, registeredPlugins, registeredPluginIDs, - getRegisteredPluginsSort_EVM_Ahead, getRegisteredWeb3Networks, getRegisteredWeb3Providers, } from './manager/store' diff --git a/packages/plugin-infra/src/manager/store.ts b/packages/plugin-infra/src/manager/store.ts index c8f5d8e65144..3886308a1f83 100644 --- a/packages/plugin-infra/src/manager/store.ts +++ b/packages/plugin-infra/src/manager/store.ts @@ -19,7 +19,7 @@ export function registerPlugin(def: Plugin.DeferredDefinition) { getRegisteredWeb3Providers_memo.cache.clear?.() } -export function getRegisteredPluginsSort_EVM_Ahead() { +function getRegisteredPluginsSort_EVM_Ahead() { return [...__registered.values()].sort(sort_EVM_ahead) } diff --git a/packages/plugin-infra/src/context/index.tsx b/packages/plugin-infra/src/web3/Context.tsx similarity index 100% rename from packages/plugin-infra/src/context/index.tsx rename to packages/plugin-infra/src/web3/Context.tsx diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts index 8ae5098f51cd..8342491701df 100644 --- a/packages/plugin-infra/src/web3/index.ts +++ b/packages/plugin-infra/src/web3/index.ts @@ -16,3 +16,4 @@ export * from './useTransactionType' export * from './useWallet' export * from './useWalletPrimary' export * from './useWallets' +export * from './Context' diff --git a/packages/plugin-infra/src/web3/useAccount.ts b/packages/plugin-infra/src/web3/useAccount.ts index c6195739dc45..5f5a3656711c 100644 --- a/packages/plugin-infra/src/web3/useAccount.ts +++ b/packages/plugin-infra/src/web3/useAccount.ts @@ -1,5 +1,5 @@ import { first } from 'lodash-es' -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' /** * Get the address of the default wallet diff --git a/packages/plugin-infra/src/web3/useAllowTestnet.ts b/packages/plugin-infra/src/web3/useAllowTestnet.ts index ff5371c7c0a4..2a196e89052a 100644 --- a/packages/plugin-infra/src/web3/useAllowTestnet.ts +++ b/packages/plugin-infra/src/web3/useAllowTestnet.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useAllowTestnet(pluginID?: string) { return usePluginWeb3StateContext(pluginID).allowTestnet diff --git a/packages/plugin-infra/src/web3/useAssetType.ts b/packages/plugin-infra/src/web3/useAssetType.ts index 636f75a58cf7..16f5d3d8a767 100644 --- a/packages/plugin-infra/src/web3/useAssetType.ts +++ b/packages/plugin-infra/src/web3/useAssetType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useAssetType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).assetType diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts index ed23058462ff..6d71d7d66101 100644 --- a/packages/plugin-infra/src/web3/useBalance.ts +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' /** * Get the current block number diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index 2e47e9acca5f..fd5516fbec85 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' /** * Get the current block number of current chain diff --git a/packages/plugin-infra/src/web3/useChainDetailed.ts b/packages/plugin-infra/src/web3/useChainDetailed.ts index 142184f0e802..93de566196c5 100644 --- a/packages/plugin-infra/src/web3/useChainDetailed.ts +++ b/packages/plugin-infra/src/web3/useChainDetailed.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useChainDetailed(pluginID?: string) { return usePluginWeb3StateContext(pluginID).chainDetailed diff --git a/packages/plugin-infra/src/web3/useChainId.ts b/packages/plugin-infra/src/web3/useChainId.ts index 9bf633b9e6f0..483ab9699c0f 100644 --- a/packages/plugin-infra/src/web3/useChainId.ts +++ b/packages/plugin-infra/src/web3/useChainId.ts @@ -1,5 +1,5 @@ import { useChainDetailed } from '.' -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' /** * Get the chain id which is using by the given (or default) wallet diff --git a/packages/plugin-infra/src/web3/useCollectibleType.ts b/packages/plugin-infra/src/web3/useCollectibleType.ts index 810927d5205e..cbcdcfafab18 100644 --- a/packages/plugin-infra/src/web3/useCollectibleType.ts +++ b/packages/plugin-infra/src/web3/useCollectibleType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useCollectibleType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).collectibleType diff --git a/packages/plugin-infra/src/web3/useCurrencyType.ts b/packages/plugin-infra/src/web3/useCurrencyType.ts index f174b469bdae..a5a65ab46880 100644 --- a/packages/plugin-infra/src/web3/useCurrencyType.ts +++ b/packages/plugin-infra/src/web3/useCurrencyType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useCurrencyType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).currencyType diff --git a/packages/plugin-infra/src/web3/useNameType.ts b/packages/plugin-infra/src/web3/useNameType.ts index 8b1b1bb3ea73..3bb54d40239f 100644 --- a/packages/plugin-infra/src/web3/useNameType.ts +++ b/packages/plugin-infra/src/web3/useNameType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useNameType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).nameType diff --git a/packages/plugin-infra/src/web3/useNetworkType.ts b/packages/plugin-infra/src/web3/useNetworkType.ts index 789238ecabc6..fd7941399afb 100644 --- a/packages/plugin-infra/src/web3/useNetworkType.ts +++ b/packages/plugin-infra/src/web3/useNetworkType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useNetworkType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).networkType diff --git a/packages/plugin-infra/src/web3/useProviderType.ts b/packages/plugin-infra/src/web3/useProviderType.ts index 6d39df26a938..6f6fc98d8759 100644 --- a/packages/plugin-infra/src/web3/useProviderType.ts +++ b/packages/plugin-infra/src/web3/useProviderType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useProviderType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).providerType diff --git a/packages/plugin-infra/src/web3/useTokenPrice.ts b/packages/plugin-infra/src/web3/useTokenPrice.ts index 836cea0da45a..c0ff6434f61a 100644 --- a/packages/plugin-infra/src/web3/useTokenPrice.ts +++ b/packages/plugin-infra/src/web3/useTokenPrice.ts @@ -1,5 +1,5 @@ import type { CurrencyType } from '../web3-types' -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useTokenPrice(id: string, currencyType: string, pluginID?: string) { const { prices } = usePluginWeb3StateContext(pluginID) ?? {} diff --git a/packages/plugin-infra/src/web3/useTransactionType.ts b/packages/plugin-infra/src/web3/useTransactionType.ts index c08283474f26..fb5671a16343 100644 --- a/packages/plugin-infra/src/web3/useTransactionType.ts +++ b/packages/plugin-infra/src/web3/useTransactionType.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useTransactionType(pluginID?: string) { return usePluginWeb3StateContext(pluginID).transactionType diff --git a/packages/plugin-infra/src/web3/useWallet.ts b/packages/plugin-infra/src/web3/useWallet.ts index 5086bcae0a42..bbd79a4d9db7 100644 --- a/packages/plugin-infra/src/web3/useWallet.ts +++ b/packages/plugin-infra/src/web3/useWallet.ts @@ -1,5 +1,5 @@ import { useAccount } from '.' -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useWallet(pluginID?: string) { const account = useAccount(pluginID) diff --git a/packages/plugin-infra/src/web3/useWalletPrimary.ts b/packages/plugin-infra/src/web3/useWalletPrimary.ts index a83a6ec85a3f..6ecd3d3a1f7b 100644 --- a/packages/plugin-infra/src/web3/useWalletPrimary.ts +++ b/packages/plugin-infra/src/web3/useWalletPrimary.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useWalletPrimary(pluginID?: string) { return usePluginWeb3StateContext(pluginID).walletPrimary diff --git a/packages/plugin-infra/src/web3/useWallets.ts b/packages/plugin-infra/src/web3/useWallets.ts index ff13acb9163a..e89d41b689ef 100644 --- a/packages/plugin-infra/src/web3/useWallets.ts +++ b/packages/plugin-infra/src/web3/useWallets.ts @@ -1,4 +1,4 @@ -import { usePluginWeb3StateContext } from '../context' +import { usePluginWeb3StateContext } from './Context' export function useWallets(type?: string, pluginID?: string) { return usePluginWeb3StateContext(pluginID).wallets From b86a227c8ff6434216bf22675594382d5224eb49 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 15 Nov 2021 17:34:13 +0800 Subject: [PATCH 29/41] fix: duplicated dependency --- packages/web3-shared/evm/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/web3-shared/evm/package.json b/packages/web3-shared/evm/package.json index 76fa714e1fd3..d3a461d3543f 100644 --- a/packages/web3-shared/evm/package.json +++ b/packages/web3-shared/evm/package.json @@ -8,7 +8,6 @@ "@ensdomains/address-encoder": "^0.2.6", "@masknet/web3-constants": "workspace:*", "@masknet/web3-contracts": "workspace:*", - "@masknet/web3-contracts": "workspace:*", "@unstoppabledomains/resolution": "^5.0.1", "bignumber.js": "9.0.1", "ethereum-blockies": "^0.1.1", From 7243367a3f046458de31592ad9d641f4a93984b2 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 16 Nov 2021 15:50:10 +0800 Subject: [PATCH 30/41] refactor: provider & network icons --- cspell.json | 1 + .../TokenTableRow/ChangeNetworkTip.tsx | 4 +- .../components/WalletStateBar/index.tsx | 2 +- packages/dashboard/src/web3/context.ts | 8 +- .../injected-script/sdk/bridgedEthereum.ts | 4 +- .../InjectedComponents/ToolboxUnstyled.tsx | 12 +- .../mask/src/components/shared/WalletIcon.tsx | 65 ------- .../src/components/shared/WalletStatusBox.tsx | 61 +++---- .../EthereumServices/provider.ts | 8 +- .../EthereumServices/providers/Injected.ts | 11 +- .../EthereumServices/send.ts | 8 +- .../EthereumServices/web3.ts | 4 +- .../components/WalletStateBar/index.tsx | 2 +- .../UI/components/InjectedProviderBridge.tsx | 20 +-- .../UI/components/ProviderIconClickBait.tsx | 43 +++-- .../src/plugins/EVM}/assets/coin98.png | Bin .../src/plugins/EVM}/assets/coinbase.png | Bin .../src/plugins/EVM}/assets/mathwallet.png | Bin packages/mask/src/plugins/EVM/base.ts | 3 +- packages/mask/src/plugins/EVM/constants.ts | 6 +- .../EVM/hooks/useInjectedProviderType.ts | 16 +- packages/mask/src/plugins/EVM/messages.ts | 4 +- .../SNSAdaptor/components/DrawDialog.tsx | 2 +- .../plugins/PoolTogether/UI/NetworkView.tsx | 2 +- .../Profile/SNSAdaptor/WalletsPage.tsx | 2 +- .../ConnectionProgress.tsx | 26 ++- .../SNSAdaptor/ConnectWalletDialog/index.tsx | 23 +-- .../PluginProviderRender.tsx | 13 +- .../SelectProviderDialog/ProviderIcon.tsx | 1 + .../SNSAdaptor/SelectProviderDialog/index.tsx | 4 +- .../src/plugins/Wallet/services/account.ts | 10 +- packages/mask/src/plugins/Wallet/settings.ts | 11 -- packages/mask/src/web3/context.ts | 14 +- packages/plugin-infra/src/web3/Context.tsx | 6 +- .../src/web3/getRegisteredPluginNetwork.ts | 7 - .../src/web3/getRegisteredPluginProvider.ts | 6 - packages/plugin-infra/src/web3/index.ts | 4 +- .../src/web3/useNetworkDescriptor.ts | 11 ++ .../src/web3/useProviderDescriptor.ts | 11 ++ packages/shared/assets/arbitrum.png | Bin 35907 -> 0 bytes packages/shared/assets/binance.png | Bin 3471 -> 0 bytes packages/shared/assets/ethereum.png | Bin 692 -> 0 bytes packages/shared/assets/maskwallet.png | Bin 18209 -> 0 bytes packages/shared/assets/metamask.png | Bin 16590 -> 0 bytes packages/shared/assets/polygon.png | Bin 1841 -> 0 bytes packages/shared/assets/walletconnect.png | Bin 177386 -> 0 bytes packages/shared/assets/xdai.png | Bin 3409 -> 0 bytes .../src/UI/components/ChainIcon/index.tsx | 2 +- .../src/UI/components/ImageIcon/index.tsx | 9 +- .../src/UI/components/NetworkIcon/index.tsx | 34 ---- .../src/UI/components/ProviderIcon/index.tsx | 57 ------ .../src/UI/components/WalletIcon/index.tsx | 13 +- packages/web3-shared/evm/context/index.tsx | 2 - packages/web3-shared/evm/context/type.ts | 2 - .../evm/hooks/useInjectedProviderType.ts | 5 - packages/web3-shared/evm/pipes/index.ts | 57 +++--- packages/web3-shared/evm/types/index.ts | 10 +- pnpm-lock.yaml | 166 +++++++++++++++++- 58 files changed, 381 insertions(+), 411 deletions(-) delete mode 100644 packages/mask/src/components/shared/WalletIcon.tsx rename packages/{shared => mask/src/plugins/EVM}/assets/coin98.png (100%) rename packages/{shared => mask/src/plugins/EVM}/assets/coinbase.png (100%) rename packages/{shared => mask/src/plugins/EVM}/assets/mathwallet.png (100%) delete mode 100644 packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts delete mode 100644 packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts create mode 100644 packages/plugin-infra/src/web3/useNetworkDescriptor.ts create mode 100644 packages/plugin-infra/src/web3/useProviderDescriptor.ts delete mode 100644 packages/shared/assets/arbitrum.png delete mode 100644 packages/shared/assets/binance.png delete mode 100644 packages/shared/assets/ethereum.png delete mode 100644 packages/shared/assets/maskwallet.png delete mode 100644 packages/shared/assets/metamask.png delete mode 100644 packages/shared/assets/polygon.png delete mode 100644 packages/shared/assets/walletconnect.png delete mode 100644 packages/shared/assets/xdai.png delete mode 100644 packages/shared/src/UI/components/NetworkIcon/index.tsx delete mode 100644 packages/shared/src/UI/components/ProviderIcon/index.tsx delete mode 100644 packages/web3-shared/evm/hooks/useInjectedProviderType.ts diff --git a/cspell.json b/cspell.json index 847772ebfb61..4f059609b814 100644 --- a/cspell.json +++ b/cspell.json @@ -314,6 +314,7 @@ "onflow", "unauthenticate", "mathwallet", + "walletlink", "rpcs" ], "ignoreRegExpList": ["/@servie/"], diff --git a/packages/dashboard/src/pages/Wallets/components/TokenTableRow/ChangeNetworkTip.tsx b/packages/dashboard/src/pages/Wallets/components/TokenTableRow/ChangeNetworkTip.tsx index 71494619023b..8ea354041fbb 100644 --- a/packages/dashboard/src/pages/Wallets/components/TokenTableRow/ChangeNetworkTip.tsx +++ b/packages/dashboard/src/pages/Wallets/components/TokenTableRow/ChangeNetworkTip.tsx @@ -43,7 +43,9 @@ export const ChangeNetworkTip = memo(({ chainId }) => { break case ProviderType.MetaMask: case ProviderType.WalletConnect: - case ProviderType.Injected: + case ProviderType.Coin98: + case ProviderType.WalletLink: + case ProviderType.MathWallet: setConnectWalletDialog({ open: true, providerType, diff --git a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx index 2303cb795500..c0b0fe06e9dc 100644 --- a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx @@ -129,7 +129,7 @@ export const WalletStateBarUI: FC = ({ {/* */} - + {walletName} diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index bd538cba9a7e..d76e131164d2 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -13,7 +13,6 @@ import { Web3ProviderType, SendOverrides, RequestOptions, - InjectedProviderType, } from '@masknet/web3-shared-evm' import { Services, Messages, PluginServices, PluginMessages } from '../API' @@ -30,7 +29,8 @@ export const Web3Context: Web3ProviderType = { account: createSubscriptionFromAsync( async () => { const providerType = await Services.Settings.getCurrentSelectedWalletProvider() - if (providerType === ProviderType.Injected) return '' + if ([ProviderType.Coin98, ProviderType.WalletLink, ProviderType.MathWallet].includes(providerType)) + return '' return Services.Settings.getSelectedWalletAddress() }, '', @@ -66,10 +66,6 @@ export const Web3Context: Web3ProviderType = { NetworkType.Ethereum, Messages.events.currentNetworkSettings.on, ), - injectedProviderType: { - getCurrentValue: () => InjectedProviderType.Unknown, - subscribe: () => noop, - }, walletPrimary: createSubscriptionFromAsync( PluginServices.Wallet.getWalletPrimary, null, diff --git a/packages/injected-script/sdk/bridgedEthereum.ts b/packages/injected-script/sdk/bridgedEthereum.ts index 2ec002618d20..ea5bd35560f7 100644 --- a/packages/injected-script/sdk/bridgedEthereum.ts +++ b/packages/injected-script/sdk/bridgedEthereum.ts @@ -65,7 +65,9 @@ export interface BridgedEthereumProvider { /** Add event listener */ on(event: string, callback: (...args: any) => void): () => void /** Access primitive property on the window.ethereum object. */ - getProperty(key: 'isMetaMask' | 'isCoin98' | 'isMathWallet' | 'isWalletLink'): Promise + getProperty( + key: 'isMaskWallet' | 'isMetaMask' | 'isCoin98' | 'isMathWallet' | 'isWalletLink', + ): Promise /** MetaMask only, experimental API. */ _metamaskIsUnlocked(): Promise /** Call window.ethereum.isConnected() */ diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 7e9293586306..745d9b081ec2 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -25,6 +25,9 @@ import { import { useActivatedPluginSNSAdaptor_withSupportOperateChain, useActivatedPluginsSNSAdaptor, + useNetworkDescriptor, + useProviderDescriptor, + useProviderType, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' import { Image } from '../shared/Image' @@ -117,6 +120,9 @@ export function ToolboxHintUnstyled(props: ToolboxHintProps) { shouldDisplayChainIndicator, } = useToolbox() + const networkDescriptor = useNetworkDescriptor() + const providerDescriptor = useProviderDescriptor() + return ( <> @@ -137,7 +143,11 @@ export function ToolboxHintUnstyled(props: ToolboxHintProps) { {isWalletValid ? ( - + ) : ( )} diff --git a/packages/mask/src/components/shared/WalletIcon.tsx b/packages/mask/src/components/shared/WalletIcon.tsx deleted file mode 100644 index 386820d3dac6..000000000000 --- a/packages/mask/src/components/shared/WalletIcon.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import classNames from 'classnames' -import { makeStyles } from '@masknet/theme' -import { NetworkIcon, ProviderIcon, useValueRef, useStylesExtends } from '@masknet/shared' -import { useChainId, getNetworkTypeFromChainId } from '@masknet/web3-shared-evm' -import { currentInjectedProviderSettings, currentProviderSettings } from '../../plugins/Wallet/settings' - -interface StyleProps { - size: number -} - -const useStyles = makeStyles()((theme, props) => ({ - root: { - position: 'relative', - display: 'flex', - height: props.size, - width: props.size, - }, - mainIcon: { - width: '100%', - height: '100%', - }, - badgeIcon: { - position: 'absolute', - right: -2, - bottom: -2, - }, - providerIcon: {}, - networkIcon: { - borderRadius: '50%', - }, -})) - -interface WalletIconProps extends withClasses<'networkIcon' | 'providerIcon'> { - size?: number - badgeSize?: number -} - -export const WalletIcon = (props: WalletIconProps) => { - const { size = 24, badgeSize = 14 } = props - const chainId = useChainId() - const classes = useStylesExtends(useStyles({ size: badgeSize > size ? badgeSize : size }), props) - const selectedNetwork = getNetworkTypeFromChainId(chainId) - const selectedWalletProvider = useValueRef(currentProviderSettings) - const selectedWalletInjectedProvider = useValueRef(currentInjectedProviderSettings) - - return ( -
    - size ? classes.badgeIcon : classes.mainIcon, classes.networkIcon), - }} - size={size} - networkType={selectedNetwork} - /> - size ? classes.mainIcon : classes.badgeIcon, classes.providerIcon), - }} - size={badgeSize} - providerType={selectedWalletProvider} - injectedProviderType={selectedWalletInjectedProvider} - /> -
    - ) -} diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index 80fd5c41d01f..53bd39bc330b 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -2,21 +2,20 @@ import { useCallback } from 'react' import { useCopyToClipboard } from 'react-use' import { Copy, ExternalLink } from 'react-feather' import classNames from 'classnames' -import { ProviderType, resolveAddressLinkOnExplorer, useWallet, useChainId, resolveInjectedProviderName } from '@masknet/web3-shared-evm' +import { + ProviderType, + resolveAddressLinkOnExplorer, + useWallet, + useChainId, + resolveProviderName, +} from '@masknet/web3-shared-evm' import { Button, Link, Typography } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' -import { - FormattedAddress, - useRemoteControlledDialog, - useValueRef, - useSnackbarCallback, - WalletIcon, -} from '@masknet/shared' +import { useNetworkDescriptor, useProviderDescriptor, useProviderType } from '@masknet/plugin-infra' +import { FormattedAddress, useRemoteControlledDialog, useSnackbarCallback, WalletIcon } from '@masknet/shared' import { WalletMessages } from '../../plugins/Wallet/messages' -import { currentProviderSettings } from '../../plugins/Wallet/settings' import { useI18N } from '../../utils' import Services from '../../extension/service' -import { useInjectedProviderType } from '../../plugins/EVM/hooks' const useStyles = makeStyles()((theme) => ({ content: { @@ -63,17 +62,8 @@ const useStyles = makeStyles()((theme) => ({ marginRight: theme.spacing(1), color: '#1C68F3', }, - networkIcon: { - backgroundColor: '#F6F8F8 !important', - border: '1px solid #ffffff', - borderRadius: '50%', - position: 'absolute', - right: -6, - bottom: -4, - }, - providerIcon: { - backgroundColor: 'none !important', - }, + networkIcon: {}, + providerIcon: {}, connectButtonWrapper: { display: 'flex', justifyContent: 'center', @@ -89,8 +79,10 @@ export function WalletStatusBox() { const chainId = useChainId() const selectedWallet = useWallet() const { setDialog: setRenameDialog } = useRemoteControlledDialog(WalletMessages.events.walletRenameDialogUpdated) - const selectedProviderType = useValueRef(currentProviderSettings) - const injectedProviderType = useInjectedProviderType() + + const providerType = useProviderType() + const providerDescriptor = useProviderDescriptor() + const networkDescriptor = useNetworkDescriptor() //#region copy addr to clipboard const [, copyToClipboard] = useCopyToClipboard() @@ -120,22 +112,29 @@ export function WalletStatusBox() { //#endregion const onDisconnect = useCallback(async () => { - if (selectedProviderType !== ProviderType.WalletConnect) return + if (providerType !== ProviderType.WalletConnect) return setWalletConnectDialog({ open: true, uri: await Services.Ethereum.createConnectionURI(), }) - }, [selectedProviderType, setWalletConnectDialog]) + }, [providerType, setWalletConnectDialog]) const onChange = useCallback(() => { openSelectProviderDialog() }, [openSelectProviderDialog]) + console.log({ + networkDescriptor, + providerDescriptor, + }) + return selectedWallet ? (
    - - {selectedProviderType === ProviderType.Injected - ? resolveInjectedProviderName(injectedProviderType) - : selectedWallet.name} - + {providerDescriptor?.name}
    - {selectedProviderType === ProviderType.WalletConnect ? ( + {providerType === ProviderType.WalletConnect ? (
    diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx index b3d3a58951ee..1e67ecd1444f 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx @@ -38,6 +38,7 @@ export interface ProviderIconProps { onClick?: () => void ButtonBaseProps?: Partial } + export function ProviderIcon({ icon, name, onClick, ButtonBaseProps }: ProviderIconProps) { const { classes } = useStyles() return ( diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 1e507bb73b63..bf42635912bc 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -6,8 +6,8 @@ import { getRegisteredWeb3Networks, getRegisteredWeb3Providers, useActivatedPluginWeb3UI, + useNetworkDescriptor, useNetworkType, - getRegisteredPluginNetwork, } from '@masknet/plugin-infra' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' @@ -51,7 +51,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const undeterminedWeb3UI = useActivatedPluginWeb3UI(undeterminedPluginID) const undeterminedNetworkType = useNetworkType(undeterminedPluginID) - const undeterminedNetwork = getRegisteredPluginNetwork(undeterminedPluginID, undeterminedNetworkType) + const undeterminedNetwork = useNetworkDescriptor(undeterminedNetworkType, undeterminedPluginID) const networks = getRegisteredWeb3Networks() const providers = getRegisteredWeb3Providers() diff --git a/packages/mask/src/plugins/Wallet/services/account.ts b/packages/mask/src/plugins/Wallet/services/account.ts index 68729c672b0d..3cfe0f9c6508 100644 --- a/packages/mask/src/plugins/Wallet/services/account.ts +++ b/packages/mask/src/plugins/Wallet/services/account.ts @@ -4,7 +4,6 @@ import { ChainId, getChainIdFromNetworkType, getNetworkTypeFromChainId, - InjectedProviderType, NetworkType, ProviderType, resolveProviderName, @@ -17,7 +16,6 @@ import { currentMaskWalletNetworkSettings, currentNetworkSettings, currentProviderSettings, - currentInjectedProviderSettings, } from '../settings' import { Flags, hasNativeAPI, nativeAPI } from '../../../utils' import { getWallets, hasWallet, updateWallet } from '.' @@ -29,7 +27,6 @@ export async function updateAccount( chainId?: ChainId networkType?: NetworkType providerType?: ProviderType - injectedProviderType?: InjectedProviderType } = {}, ) { if (options.chainId && !options.networkType) options.networkType = getNetworkTypeFromChainId(options.chainId) @@ -39,7 +36,7 @@ export async function updateAccount( if ((options.account && !options.providerType) || (options.account === undefined && options.providerType)) throw new Error('Account and provider type must be updating both') - const { name, account, chainId, providerType, networkType, injectedProviderType } = options + const { name, account, chainId, providerType, networkType } = options // update wallet in the DB if ( @@ -64,7 +61,6 @@ export async function updateAccount( if (networkType) currentNetworkSettings.value = networkType if (account !== undefined) currentAccountSettings.value = account if (providerType) currentProviderSettings.value = providerType - if (injectedProviderType) currentInjectedProviderSettings.value = injectedProviderType if (currentProviderSettings.value === ProviderType.MaskWallet) { await updateMaskAccount({ account, @@ -91,16 +87,14 @@ export async function resetAccount( chainId?: ChainId networkType?: NetworkType providerType?: ProviderType - injectedProviderType?: InjectedProviderType } = {}, ) { - const { account = '', chainId, networkType, providerType, injectedProviderType } = options + const { account = '', chainId, networkType, providerType } = options currentAccountSettings.value = account if (providerType === ProviderType.MaskWallet) currentMaskWalletAccountSettings.value = account if (chainId) currentChainIdSettings.value = chainId if (networkType) currentNetworkSettings.value = networkType if (providerType) currentProviderSettings.value = providerType - if (injectedProviderType) currentInjectedProviderSettings.value = injectedProviderType } export async function setDefaultWallet() { diff --git a/packages/mask/src/plugins/Wallet/settings.ts b/packages/mask/src/plugins/Wallet/settings.ts index aa2f61fe48e2..205d1531c8d6 100644 --- a/packages/mask/src/plugins/Wallet/settings.ts +++ b/packages/mask/src/plugins/Wallet/settings.ts @@ -9,7 +9,6 @@ import { PortfolioProvider, ProviderType, LockStatus, - InjectedProviderType, } from '@masknet/web3-shared-evm' import { PLUGIN_IDENTIFIER } from './constants' import { isEqual } from 'lodash-es' @@ -74,16 +73,6 @@ export const currentProviderSettings = createGlobalSettings( }, ) -/** - * The injected provider type of the selected wallet - */ -export const currentInjectedProviderSettings = createGlobalSettings( - `${PLUGIN_IDENTIFIER}+selectedWalletInjectedProvider`, - InjectedProviderType.Unknown, - { - primary: () => 'DO NOT DISPLAY IT IN UI', - }, -) /** * The default portfolio data provider */ diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 1ac30f73e64c..5a6f2f2f81f7 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -7,7 +7,7 @@ import { EthereumTokenType, ProviderType, Web3ProviderType, - resolveInjectedProviderIdentityKey, + resolveProviderIdentityKey, } from '@masknet/web3-shared-evm' import { bridgedEthereumProvider } from '@masknet/injected-script' import { @@ -23,7 +23,6 @@ import { currentMaskWalletNetworkSettings, currentMaskWalletAccountSettings, currentMaskWalletBalanceSettings, - currentInjectedProviderSettings, } from '../plugins/Wallet/settings' import { WalletMessages, WalletRPC } from '../plugins/Wallet/messages' import type { InternalSettings } from '../settings/createSettings' @@ -60,7 +59,6 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy await currentAccountSettings.readyPromise await currentMaskWalletAccountSettings.readyPromise await currentProviderSettings.readyPromise - await currentInjectedProviderSettings.readyPromise } catch (error) { // do nothing } @@ -69,11 +67,11 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy const providerType = currentProviderSettings.value if (location.href.includes('popups.html')) return account - if (providerType !== ProviderType.Injected) return account + if (![ProviderType.Coin98, ProviderType.WalletLink, ProviderType.MathWallet].includes(providerType)) + return account try { - const injectedProviderType = currentInjectedProviderSettings.value - const propertyKey = resolveInjectedProviderIdentityKey(injectedProviderType) + const propertyKey = resolveProviderIdentityKey(providerType) if (!propertyKey) return '' const propertyValue = await bridgedEthereumProvider.getProperty(propertyKey) if (propertyValue === true) return account @@ -87,8 +85,7 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy const a = currentAccountSettings.addListener(callback) const b = currentMaskWalletAccountSettings.addListener(callback) const c = currentProviderSettings.addListener(callback) - const d = currentInjectedProviderSettings.addListener(callback) - return () => void [a(), b(), c(), d()] + return () => void [a(), b(), c()] }, ), balance: createSubscriptionFromSettings(isMask ? currentMaskWalletBalanceSettings : currentBalanceSettings), @@ -104,7 +101,6 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy ? createStaticSubscription(() => ProviderType.MaskWallet) : createSubscriptionFromSettings(currentProviderSettings), networkType: createSubscriptionFromSettings(isMask ? currentMaskWalletNetworkSettings : currentNetworkSettings), - injectedProviderType: createSubscriptionFromSettings(currentInjectedProviderSettings), erc20Tokens: createSubscriptionFromAsync( () => WalletRPC.getTokens(EthereumTokenType.ERC20), [], diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index d23b53691f24..e2fe502d7bbb 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -77,12 +77,16 @@ function usePluginsWeb3State() { } } +export function usePluginIDContext() { + return useContext(PluginIDContext) +} + const PluginsWeb3StateContext = createContainer(usePluginsWeb3State) export const usePluginsWeb3StateContext = PluginsWeb3StateContext.useContainer export function usePluginWeb3StateContext(expectedPluginID?: string) { - const pluginID = useContext(PluginIDContext) + const pluginID = usePluginIDContext() const pluginsWeb3State = usePluginsWeb3StateContext() // @ts-ignore return pluginsWeb3State[expectedPluginID ?? pluginID] as ReturnType diff --git a/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts b/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts deleted file mode 100644 index d9f6bf49fd34..000000000000 --- a/packages/plugin-infra/src/web3/getRegisteredPluginNetwork.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getPluginDefine } from '../manager/store' - -export function getRegisteredPluginNetwork(pluginID: string, networkTypeOrID?: string) { - return getPluginDefine(pluginID)?.declareWeb3Networks?.find( - (x) => x.type === networkTypeOrID || x.ID === networkTypeOrID, - ) -} diff --git a/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts b/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts deleted file mode 100644 index 278b83c8772b..000000000000 --- a/packages/plugin-infra/src/web3/getRegisteredPluginProvider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { getPluginDefine } from '../manager/store' -export function getRegisteredPluginProvider(pluginID: string, providerTypeOrID?: string) { - return getPluginDefine(pluginID)?.declareWeb3Providers?.find( - (x) => x.ID === providerTypeOrID || x.type === providerTypeOrID, - ) -} diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts index 8342491701df..49099bb69593 100644 --- a/packages/plugin-infra/src/web3/index.ts +++ b/packages/plugin-infra/src/web3/index.ts @@ -1,5 +1,3 @@ -export * from './getRegisteredPluginNetwork' -export * from './getRegisteredPluginProvider' export * from './useAccount' export * from './useAllowTestnet' export * from './useAssetType' @@ -11,6 +9,8 @@ export * from './useCollectibleType' export * from './useNameType' export * from './useNetworkType' export * from './useProviderType' +export * from './useNetworkDescriptor' +export * from './useProviderDescriptor' export * from './useTokenPrice' export * from './useTransactionType' export * from './useWallet' diff --git a/packages/plugin-infra/src/web3/useNetworkDescriptor.ts b/packages/plugin-infra/src/web3/useNetworkDescriptor.ts new file mode 100644 index 000000000000..7ee5b025312f --- /dev/null +++ b/packages/plugin-infra/src/web3/useNetworkDescriptor.ts @@ -0,0 +1,11 @@ +import { useNetworkType, usePluginIDContext } from '.' +import { getPluginDefine } from '..' + +export function useNetworkDescriptor(expectedNetworkTypeOrID?: string, expectedPluginID?: string) { + const pluginID = usePluginIDContext() + const networkType = useNetworkType() + + return getPluginDefine(expectedPluginID ?? pluginID)?.declareWeb3Networks?.find((x) => + [x.type, x.ID].includes(expectedNetworkTypeOrID ?? networkType ?? ''), + ) +} diff --git a/packages/plugin-infra/src/web3/useProviderDescriptor.ts b/packages/plugin-infra/src/web3/useProviderDescriptor.ts new file mode 100644 index 000000000000..5bc321a62508 --- /dev/null +++ b/packages/plugin-infra/src/web3/useProviderDescriptor.ts @@ -0,0 +1,11 @@ +import { useProviderType, usePluginIDContext } from '.' +import { getPluginDefine } from '..' + +export function useProviderDescriptor(expectedProviderTypeOrID?: string, expectedPluginID?: string) { + const pluginID = usePluginIDContext() + const providerType = useProviderType() + + return getPluginDefine(expectedPluginID ?? pluginID)?.declareWeb3Providers?.find((x) => + [x.type, x.ID].includes(expectedProviderTypeOrID ?? providerType ?? ''), + ) +} diff --git a/packages/shared/assets/arbitrum.png b/packages/shared/assets/arbitrum.png deleted file mode 100644 index 9acea4e36db9e5b8c9c6da9693fc5fa41dedfaf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35907 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 diff --git a/packages/shared/assets/ethereum.png b/packages/shared/assets/ethereum.png deleted file mode 100644 index 44ff0159cfe4ddbad1671c32d92117d56b3ab968..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!|1AIbUfwV_NhDSsikPHYY@Q6qU zqg0OwAWHL$OmhzhN&y)_E>H^0jm-3jNb!hF3rI-tib{142ck5us4RD&;>a|&Fpw_K z@O00}6wmNfuc&m-aF8ybplehrkOUf{U9e6SXt7#JkY6x^!hHvU`TG<0H@q*Xe}8|$ z`*??Vf&2;Q4c7Mute;RYA-}&rz~Fqv=Z!iH42&l{T^vIy;@)1rnfKU$hczH*Q%Ys$ z>2`(D~Sb7WcP6ts+g#i~`SwB$UeH>>*U7O1-BFz~Em zWVG0n@t90CDj@KS8{=ogIhZtw4pH#Gp+?Ba~mZRQ+x&lR%tyX~l;aQ@?u!nf?7CkJ<4`g&7B{{6Lm4~`v` zPY=GqBfeX7S4E1C&nnp!0jJc`WhV2yo_KPS*4FcB(?e!{Yxr*vo5@}yi)3PA@oy>dnWlF{mEOZh`>RKH@6TB=xydly@RQYfR(svpXXp+IoeUi)gJD$AUke!x_~ N;OXk;vd$@?2>`2$Ba;9C diff --git a/packages/shared/assets/maskwallet.png b/packages/shared/assets/maskwallet.png deleted file mode 100644 index 5fd7f5e7e2b8b1a9aa21d52768b5aac6ea0e9af7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18209 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 YaP<=EW}?3RlK>$9URk!&djJ3c diff --git a/packages/shared/assets/polygon.png b/packages/shared/assets/polygon.png deleted file mode 100644 index 0fddac404762ff7cfb88a99a5bb85cb797a23ff2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1841 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
      _3!-CD^poH+>4&^#`%I zOLyRk2&Cclo*Q*0;tbsQO1wMq3x9I*B4CsHf6zZ!6=Q#AKjaZ9N;HDcR5cNn$xS0NgV=Xpe(hlAV&# zlNgG>9T)i$uq>`min}pIKFkALb~T!G;S1fN>B%htGB+*vKM09EvQ_43Q+9ixY1AAe zXS|n^uMAf&TjD3ixWtzHQcPJH5?UrH0f7!l$BA~yhMylUinLzc3|pn;HWd%DYKQ}EgMX}#&|u;yus9j(bG7->V^Bu&%XSm z)}5Gt!GIsPd?9}Fe?9(^X0D5}&r`~vKJ~{0c~@Oj`1vkC<6aNnwr-J|JO*<8Pc}() zmPW1Kf5DV5nZ}Opf_2~ETI9i{k34b3Ge=kXsrxB)+Wu@;O7aef+|M|of)CsAG-CE_ zauYaFLLr%@YWx!rr`Vs(b8WJYSuPr0wh?Q8#QD5bNYiuweT`W&&luSMtB4|#- zUr6dR0JzpK0QQzs7m00-xILdNK^BJ-aEy%LhJ+(M>5&&L0czm*BA*&FIur`+hh=cK@9gv`y#o&{1 z+xQ*qh>fxHpboK&J@K2t*fDlI!b=#1Fx5KN%sYq^tKyfFjKQ8WZz~5l#cInNFQdZp zv+2M5Cr>Yb^^Ye{43(AlspAvrH~j1w{MjxVFMJkU$*wtS!l_#7QuUy$*Ems;T}4j_ z9Ee;GUZbt39F3DN(+2cz+Tl+adbi?*FFUC<)Be6Tev~tR+y5W&u9D(DxPL94~R=p<=bMe@=4Lj;qbLK79z==vO%TX@SPwo~jj^D5J>E7|5Yg~LnGZd4qg1g#Y`yO3m~)+!8(^#yyu0RU^Bx@b z*O_90*m}L}^gQv!4`QvrGn(@`mgAXujhW&rV52aP&y+O}Ci9$|gDrkZKLD+8(K?xm zZ6cIT;)&4>uRR!cI`1I8#+8@lJMMRCx#0T!+H;sX8Lcw#!k6wZPxys1D9O5RE089& zp5h&hp?xfb8ld}w7{#t&q z&;Ih3ck#L@5X-@F*DVWN&tk^Z%ew2ht!`hJQ~`9X8&5G?c>H8ES(1)1N1a#ZkHp4K zS&q9!wwiJxcw)hPGGJ^p3X}Ci`SLo?(V)r1nY{e}?7a)LuIp76_N{#mCr~J%qJmTz zwPR@Quq`UXcC^|S+RAWLVgNy;6d8`;1+-O5TO0#vN##~3G@(+G2!vZ`6D|b;AzUJa zk`M?2F%&dX1QY^tNdqM0oaF4aI-lEoFW5-~Y1L-e)b^ zaJ%ISeca)~>wokRqjXFb3}X2DTZZ&~=Myiu5)~qOS}*D|1Ov-$-VxJyzkYal{ms*l z_pBf?^fR->-CW(d`F{X{&}=?XAQBnK0dP{PAdeI>129<%2n!x4crIFRoX90V3t?y? z#M5zY)+CwRzvU+%pt!IIkO||U6M%kjqaucyRX_Cd%TVTrzasJIxEPwVoVY4~Hka8W zuogX)qrjYq8#$Pu%?<#meVj=jpkA7{?3JMR(aDkuQOZ|i`G93DBvEqd1`=PokcSUJ z6hm(LyC1<94nI%+lj;`;{li~)=bsMUmW#vJ{m9+p)A{CKZk(HXptX8vf6{;K0=~F2 z?7uv{6`YLy&u(KQXFkm#XWnJ8^8j`r5V(}L2K+~x>~xa+)4uikc>WK)bFbZzi^Jcq zAH()%z6@{vYH&aQ&{SO6fA33n2d@cuXdlq-isxR#hD&@I^Ze%?0oq?dII1|nWoqTH z7BVunu$_O6Q{doaK5FrKab88$otl-CH2~{67?DDao7_!-$df&ywSU(Vti>gUPh zcL)4f{Q{eJUgr)x?}zRlpZy)z>K)uZgKjVTj9#<14A;40&&wVhy3aj?q4op##Bg`& zMi)7>f86_R|G*9nITwH@E_@i3MU(h}{hwZReLVLS@7!zjV!wX)pVpuJzvBA%)%swZ z4yMoCJHLovu4k2=S?G0opBdt?G5H$)vXni1h}9(|=Dl~Ai$>?ANFV`=#=wst_%Qm4 zZY)-VzKWhVKqnY=BI#S4>Rg1B{I$mWnhvfr6d4E(}IyMf; z2A@0H4EtJ+7L3@&*2HiWqKyiE1~rVa%+KwsS<=-Mb{tHY_KU}cr&iJJXTYTm5pi=F z*M%crJ$xLCPQ1ypX3=5QfmPfPE+yH>#oozVEhpjTwo4|{!_E>{I9KU^bOu6A6?8ga zt}Oj!d@Zy`mB}Jb^%vKrIunn)2;J)h?;Gkz$^Lisoq$*U+&kYG*dpJa`-;2A=e<~O z{^}hZ+5q--*>vp){5&6k))|>`gTv13s}3}`93EXdVA*G7%^nV3gz}=63kR1PjPdYU z^?~Ngf8d>aJ$L05KXY^Z7xm`<`iHWQ@}jMH^y>r~UXSdHcBE_t!d`PbvL{86{hv(a z13P!id|2U&|IxAMXIj4YAxY~J%;0(9xpj45Ly*L;zkP^cf`&-|RMncNx^Sq2aP#W4 z!z#X-=pu(=n~zNpE*a2Qy|yK=#&X6#S(RH#mUPKJV;K(~>(o9C1nrfj^CJNGhG;*y zC$zHi;SI0N$-@#GHRqQx{Af?T;otrN;Of5n=o}3W>nbGHj43FIi1v+*o*dZ7QJ@&O zxgo0&YvF7p7aV@rtnP^%u3XViUN`{3qYUfD%MrYkl`S}QtRCkAj z;sgSN9>RgU3`*DGTr-oR0O>%d0go;n_VAjnb+#;{S$i3S%W=#8MG)6aDrD-;7+h5B zbuzS^$=3<3Kk;vT^KpD~eF*rG`h_;{ypH3`zyI#>jF(*Zc60C9NAyztWKYv91K>-~ z=_*6-DV?watR3w02OG|}@i@LPWuLu7Vm~y1t*;5+Hct{3`{#b=_3_0od*@!GA20u@ zo8#lY3cpjqZ*<&1b-eq=*Aw`$CwO@OKrmkjAi_K5?V^po-btc*{{t@!U|8as&jZhd z%!4j#kBD8;*br3%E=$f?bacK_!1soVhm9+MN$w=JL+wc~5-o7`t8o^RH%_;gb)|j5 zs!{Gq3dyK6<&0iSw4GU@nUeK-i`1;MjGbQ<(#{%@9Qv6Y$z(`>GJAEs%B)bgW(=}Ouf!wpmN zFIa{tK=(4>pw12FTv15bGE+Y}lncJ}Go#&|KkL&Nv34+5&1dt2^|S2%#y38E{Jr|c zHt)#Smweyd;|ss1-u%-fHpBafJ>X;ANA7GRAp z6Nd0*Bm=uuGrXbN;2~>dNf(o&41IO^woqTZ3{ZUdL{~PG&Cfq#oR8JXAZX2{CFHk^ zB>56inNQB zSK%Qcs&3dwh@zWokQhF#iLCYdVkImXB7k$5Z@CWza~ul?jR}%RO}=1HLI(!7Ck@|R z|D0F#BTBlsE?rkK8S z+C=gc)QzV=VtwrAtF{pT?%Z8=s$PZ`biiGTF!_^TgO zoBj@Vz2qluj=xa9N*TYzDP8O*P+PoDZrs4RS?*!>EiFu+a}Juf9N-9k$K}mw&l4P! zGQRe^F)}#yWxcRAp2!sk6KQZzYO?Fj>kmVx+u#)6Ct|h= z0lwO$$SlJjSQivS>M#&>PE{Ame6TO|J5cTkCt`9K-zq7p1EQcu;1)=rHG*nN&ke_6 z2}FUQYD@EG0?)w7%CgbRn&=QIe&{z}CGYynBz%}n3`|mRj@5cihyy=Q{%?NM!^iji zw|BS)z=ftS1h(*T{hs%Q&@@zJ^ zMs~50fh5^)>DclY7-y%i3S0BpGhv?j(wpP+|88yiJJ9vwSKl0e-f#YM+3A&EcEU^%m~mD1><4)I`I_xAxtGiS(dC31>h3l7-y6vRcKV#xOPieKa(-b(oWM8$^=RHH zH3LE^9BO2p?n9mgv=7nZD9aVa2{ zl|R;KMrZt0%@?QRQ9pVCVou!`E&1GAxM#dEjJ;m}^bfkz2Y^cOD)w?_#JnEkfNI@1 zu-BsxqLz)fp0esPU6zB!Jndk~`gFw@-0IR9Rf}XobNr_hV}vUVz-S&sbSBMU!KHQ& z94MNGpjb3^ooR>*Y&%(tqx@3I_K1@d($)FPrkWH8NCfQZlXAubllt3U#^}j`6{!@> zINHlFaMHo{Q;O>D_`-%8Bl?RA%wp$~HO+Z2*E)QoFR;A1-UmPRn;(9M`OR|A_^!M4 z_x}F2KiXJ5P$$(t>?thi8+*sr)vXqs5&>jkVFSn{*(2^x?U8mzu_P@U_FOpRbUsYU zZYuMFS`X(jN>NxCfN;s7$+WPVRg*7y`OWb;-}#R5A>iBp!OiiPo_Bq`$$#>%PGy_8 zFX+tv{NpyFkM3LVA1u8mQ=DyM9~DvIyn3IpPh`~zB7#BU<{}vT)V~Y!PDtqLI2{gD;|5(FVkL20@0U%;d9{}oS0laDo zV0_l65e&uh$*~ulcwx0YOXC+u&%mg-Kovr`Ime^uUBwO{(?|dCB|23LM;PlyEjD0 zfemlRZmEIf)igS=F|%*XJz$&_&%^b8@M+)j@Z0@wmixRH-#xzi@72HdPg|=2+3)nP zx<)I{NQ`LIW=I@dx=d=^X{*$xM&pPlQaHwt16*Ka zi#d8}M&ZLtFimwspxhipqUR}H<#T%CCiuiH3dUZzsk%`YAmT1hP4KXxI17h^!iRmd zsD9#-8L^&URDinbQs2O+FIjCThth{C*@Md%nZdR80H_(!+vULSf4fzmsu(>Wj$A0f zMPLT4_ScAnrYF~?T`9A;(aomsFd|h4LSN{-j`!=jIbRq|6!)j5#pad5* z;=;jMuSpdAt8*9tqtkf*yn>kzZX6X{u{-@qK=h%}j!>LeZ8s71D*W?EM(aBYd3I_vz;mzOr*817^^-os+v)}jj_4mZsyU(eA z4gYmNqHp_;W~p|yMx9KXvfpl3H7uU8V49!nQGG`L8gJOxmnn{9-mm5}k|eVp<>_;Kmce>`&UbvMRm z-$nXqQY-IcdRh3nZ}^CYYtY!cKhGSM=j*^Tyl>6z^AiW?=rf>k1eB&2AgAX2`eR3{ zF259uxzDHLLX*5>T+egk@`7J^U`yV;&d#%BpK6MzA|X$4iLXZHzzTB?)9qxSZ{&9z z*|eLnh{U=}7wt}v=V|07FVRa%3GeggK_^S{`q@XP; zmjw-7;*wv7rh^KXH{@Z%EZe`gK|W*c!~l878CiYcVJHWob-PLZFirvEi45aJG}SLS zm`WW92XFF)mK=3!djgo$sR?pE2MitNj=jb_ry&Xb!7sk~^!gBh?+Eg|D z^jY<%-EaK+bAzjRHs8%aFVqCwc}>T27|O}+)-CwF%kD2k-j;G}KX6{ft^3$V(dRrb z0xA^oh{!(j`CkUHj8QD(&gTJAS6&WrIS_o$|B;*e6Y}-(=^uLMxRZi|dmA0U{+0FX zo4*ln{-_##bKj?)(Oz9qD}3+glX{B&sc&u=*}x~>eZOSQeq^P6Lul|}zQ)`GG|qCAPQgg8+KuZav)R3T>ZgDzl8v zN^acj7CzRi<4qs*9>+g?N!A{NUCbZ#><53OME-#ottZRN3EI2#mDa=~8Rkhk8af37 zlYrIS1)bwQcQhdO} zMtjT-=~EK>QZGOwo{$J`93ihfo^kaDP1(cgI{@~)yg2_rc!HkJSxgtlA!l`mFLk8x zu?L-a;PA+LywI2d4o;k$vk#BLzCw->&IV4ea?62I{{DqfVa&L0r;zoPkZ6r@^X0_}U?S^ORlxRd7)lp7Wn*I_uWQE(X}@ z5u8tFd&36=zB}^p-8;wUJoPy4yEF7O_-$bF)jwFjzWG~HZ3#~CWrDSzpQ$Bwe21Xs z{YG62;tQuy{TS8|1fW-{(NFtpLnxsgqpy+%c3hi1W;wa9!1U`y!4p9!HXbb2y?OiG zoc5p9If)o}A9;#b4R9S3);VDr&kxlr@W5W;1E$-u)!X(ISzu1PzQGNF^ipaOsUd2? z#0w4M`C(%7VFf676f({OGYz;C+u#)ja!fsGTm9^*3D(ooKLUiOUcg_5;=wa>!G?!q zN+MRd;)iE`WI-+{%%ecSVdJuS;7TljX$EY4HNXPBMss_U8$9?%9t)^AZOEEGp~|jL zaO5rrQy~v#Q+mWCzvYkyb2M$v!@kn1oALnXhke9Vj+mL1xk>5npcY+oeps;PhGzx5k6VTyiR~sT`5~EjV@?xW^0{ESQDIawrz*q6_xVtN&%}>+2Wfyscdi z*PH*RezV^Eb6$E(G1UOniaK#+L}O^T0Ry+f814_qe0BfZP?HK`Tup%oCuVpApMBA( zRx;e%UP*J7%3PO_q?18+W2O3zM<)b&weT)Y`S7^ypMpQw9h;n1t*o`Dm^6dA{zth zhW}`Q3+Jc?KCFQeFvTJK$UlgIXuIPww7nC=6JCoev(hWSRyHz3`0yc$b(vCV`8){#pm~l6CPpN9%UO@;3N#}#6h8YGI`kD^)CZ%l#(`jvWcsq; z=JDcp0PcU6>zBQ`eqjsyKBIfCqLU*nU~Prj?ffgSGR7X>E}#tXVI7}RDI)wr0cfwm z@oPhnCz*tUKNgNjQVAJbM%cAE&>*z#;3!m*lyS!mr}##kJp8+=7;DTF%=6X#n*f;7 zjyT&XrEaW~0I}@4u%_E_ju-+up-os9cJH4ASZVq9JgL9!fObwS)V%1A3s%f~Em+r? zeX#j>#&_3u0_s}=AN_%E8{Y|dxc(u-r@Y|q@!j>qU;6x@-Y&QnxNJzBbo++E+cM#V ze5CzPPJF`$Jfw6!@tVgD?qAKb|Me0B^t9hxQV=| zqWW&ho9|v9&-hb!j(5556x}p$O%wbur_cEIxhc_YoA)^gyjp0kdq02rfY|QtWnWG> z9}qsBD@3^QS`<8bMaG=BJl~aut)yvMr@yGA&9&fKWXtBV;mbBtvYfebR`$?KMkbzfn%ECXnR zCvaLX#mf$gm^&^83v4_1rkqe!%ZncXQVT+s>m#1|8$VZs?>8I6nV{49WRQ;F=Zy?> z=FgnIx@F&MMprl1gsHy^kKq>ld>}#C@FeDlLsZF`Uk3{5q=|P46J&|h6Ax;05RLab z^~`yL*oc^K^iAH|#BJuKVx)+T26>mbe`cI@ar==XyeNu^-MC z{!jRi?mIsA55IMP2zYb7`Qt|%fA9ZW6>WV)t$XcD-L=4agsuB~?$zdZqjMgEANw!M z*q?#GEPb8?5U^_&7Ux}8`)%m8{p4e9s`lg$Pw+K<@b9@g{Paw4&q>gU8c;uKPXnB7T1T;Tm~s0vcS=HO|M{+i@;z-{Qog z`z7A^yOyTcBjP)rEJVBQhPh@i&_6;Yx<*7M}3F*I&F&o^-sc$!wk zmf!Ni6YAawB+{uc%*~^VWJj^e}$Y;oak~o|g_mZ-`hDvD39wRm9lkVOv$_-xUnDNj?7BG!3 zu3C4ofH;rFNl47h53VUc5F>-}H6SK=g&AvxBd!2=g3ksff7cs;1B2re4Dn?L1dYZQ?J#uX9O!{i%o$`AHBT>*A19(Wf(cd*hJ%8W zx=R2-m`+QBG=z%dv;e-(MJD0zMvz{&lGys%tb$ol1f;0uYA{8T13fIf`da?Vj~;{{ zRG~{WXdz$H)I&57(&d12yHc;s;XQLJzqkRush^!+KSKBW>c^_Rm0b_M`R4efudg3z z{8Q`(&k*au68*4VdDqtX~bUxF-?IiMk5@KRe@z)PGAw7?%O&TEl% zM#X3k;G`WnQ0sP$KHIVB-r!>iDsVTi4Na5$1W5!S+r_BdqOS_5zcuam@-5`{4*>Pq z;AP~hh;AsmL4!nO4c19eUNB(3)lO$_B5FEM*km*XUnr;>n)Cv~KPSS$TV61eMn_<3 zv>jVw#3L7ZnP2p&Yh>%d&VUJXL+f@~{-#!kl<3ga2rNq0!xM1Vqw@!kJTUr-&a63t z^OpLfO9*z4HKcyV7yp@8*wzCeHI@BB{p6`z>av`eFOK4d5(>dS{3mJy3W9#ti4hm%tEenxoI%(tCICKwZMTEJ<7+n149G7Jmgh(#>oj1a!=Wg}nP*YhGAU?!*$AE^Ff{T%(@ z;BU}#;J@JEb6EG;fV^Y;{xnc~s7>hpX-17{u7jtLuhFWVpECF6z z$WIMg`d$`??|g}4Y%PMD+D|PGZ`LjSWJfN)ep(zkqYHK60OTs?tT(SS!~o}p(O$?= zu=0RLY*Lu`-HtV`=B+s*c;f^MUCE-<+6UlJhjImZVFW0^1q{{;AJk>0Z-{}>`_CEN z=Ji@V15Oubgp9t}_1HfE{M-M=yS%a*`34fG3#xo6Nc7nwCqswXc(d5`JHmNLo2S>kp)-Fskt+A zjGdqvmq6I2M{ucw@nsA=dDDZonjKPO@tShp5$Mrqx@4}iOwW?<^V?-U;jus1B z8S%(Am5Dfv)ZWD#2#2rdzT&!mjqbnr?*!nD>92j=-Q$PwyELJM zm58Vv*~?OkoB@nHUm$nEBMqVe5a0Lzbp0}&|KslQhPQ$b0iXHp*T)ytFEqk6^m18i zS-OoV1D6e1vNkoCJ;3uB`!X6$i(*9pl4&gl*pyTF=t*D6InfG*yW&?yq%RBiLxASH zm>tBcBYDfJQZT8DD$R@B*l&ChPZB9gymZ5+`c@nWbiqFBjUM#`;PGIpnOAZb4a8}cCrc=n)XSTc)mHN4@2o_xF# zs7n{aFF9cQQ_p_zyDIMoi}H+urumYXShTTOtz*)PplLFRo8?qw5;;MZXI&l0bZLsa zG@5h^PtvQ6t73N5^mBg2$btLd*kqSu_Jw`1Z5SL7`a7ZW;9&8(fQMZ%7=`1Lj1I?5 z8zpMn6PvyxCKn)E{o!v%upV1>)*elhDkyj;m`I?r9Opbj&-@?thwdDI?Sn7=Pc0MS zTW0$Dhw9D$YwsRE`tuaqN%oqemrwjc_4&lSqvnbCdjuNj`T=zyhUN`L#nE0HN7&3` zOiWmw`y3*rfg171&iR0xW-~XO!S{KzWyb{zoaQ4E>kp`Z&h(s*y>q*yqm2^}!S399>ox4v1=-VgY6IpMb2 z`NscFGwP=-$3<4+(4DpwCRy6%3HBepy-(q35>FEEv=w}Hd~N+G*@y2we0dS9Q% z_P+%uzy9FO@mK53|Hpr!R9VK> z$Cv$=_Z{!~t_kjRZ?OsXGe;t^K={My86tz(xlLMU;0M{yUz#= zWG*V{*8|=SZ1# zpZgTtxfvCy5*ak~Dq`@CHClTK$9%JZnnx$hVCd%`4AaG31#bivn0R9F8mRnvhV{D5 zDgv+lF^S&DHVW7AJ}1%MFcw(W`mcVL*30n2)NZ?O{YQWZsKQ=U)!g*9HSaXed zSoiu{=_F*19xOs;y^kH9iAU^7UUV4)&Gq<(`YCdsTfbiR@>$&3pZNM$-*|KUS6_4Y z__6wvKiailk&XVMmHRbJMy8Q9q6Wqoq(OaO>(>Vb;S1$N4%<^|4a@~W-uZEs3$vVm zlUhaNSi0+9Xn_ZZRTyFoHUdI~J}d$g9Yk0vc&SB``fkhB@n^sC`gmRK!9R}+{r!}0 zzB!)zgY&m)l^H(vKSHb-mFZyz4hi;k!i@!8C|(m_%Q?D-An|4Yo5%Ts2o7sr+!Xb< zO>z{pSy+Q5N{3woG3cf+#-Xmc79g{)-mCxZTYTsa&WBOqghj5W8imXg-~Osp7Bo*W?53b(FW zz|fZh#X9b25*sz~AZ0%>afs@H2(b@chzk>QIp5HL#=IcV7W;%oZ$zxPfr}m7$`%~X z#JD`4hS^ITbeC}ti%w+96&(9k#^|w{z)H0&!3UQ_KUTf}xUal>ytek@EqPtnE8u@$ zztrb>KaBpJ>qH$;N)?k7=*5H2sT3RBA{ap{jx-=$F5$x4{V49dzE#E%k^E(0dWH8X z8bHl-jy7v)m>A_OL;3(Gxq*Xy3YQjGPzau%H5fFkh|w1??3GCr1;QZ4*tX&$4!4@K zCkUy_skFe_w%Oq@ngV2c-f#j7VLcczW&hiVDB*fPOhg>@Q6VDvXdKMAC=_)BC#0Oi z?{MWu%yc0#`A8$*^}`Qb{t>_ljfAXE<3~L6jrGeqk3T%8<0h4ng-j8_?4+&L4ip;f z6yAI+W_EN%i4qZxgDw*%(ez}4f9N#MQS(5iIo{M5&UzG??BVI~7%C99=+p+sdFDv` ziWsYrZ`8Zm#!6A{a}mR%I!cAZfnkKhx=#U=opB>wXz6g6Y~b1r_RRI)0%;x0*Ktj~ zO(dxG`g|~t2|ncCymNf&AHVM{^7G_h`-b{|)4%57<0pSWkd!ITo zaksr*PQaR`k8>s<2Co%hh#+fQa5*QNz_E<}VL?1NVF`V7bbhCgoiPYAO>p`!GdcSF z@BG_3L{q0hz4H!zR*?K&X0SO+CBw@732y*PdIVed*q0#FzpQI4{J?diwtfni@;aYs zdOgB_@a7p;|L&CKG`;tC00_VHZD|BXJ}MK6N5W28KD@!%^Owy$Pwu|V2cn1L<4CRJ3H-o664{sa;; zaH)6i2cI*nUyQ-^!E~nXUndrlc`JUFibe9EGJKH+r3?oPi`?NCRMimDH=a$hnXiU{ z(}`&d>gQw1iM84O(J$Q`ANv(|k6--tSUSxUn&3w{|Mjo;n?Gdk56GDw>fGpF@FYBU!1Kmg*aOU!cg?QvAk4cL-f=D%$}lq4O>D9U*ZbfJu@2Q>OB@-Y zw;osq2Mw^1JGeBa)|jS_f(cg^q^^Y?sM}w_h9BG@AP0=W*Az=3NB$Al00M1(-a~rbM2^+LAxS2#n&0y1Y2^SwCQzw#8Wv#A!PnT`C)26ErY9!KcCDOFS5SGL&JdxO^clI}cn4Tev62 zbz{Q=J)rRhWgIk3WEr(aY%cTCG@0XW6L7eYuO3M+BkXc$KtH?eWwQ5;ghkr@?}TQq zL`z=^i?7Dl92}`Tqhh22SX^91IONhQ>5o`{VVMbW_1N*uJLym|myX=7W9U}$<-8Q; z@4ou__#eLc;rhpcQD>2lbHE$SC)At&Prp_K(b05HqfV7ot+E@vA2vYqSYTyL-!Za5 z3>zrz0r>QA0zm+7K#{*enuggiN3NpOG1$bZfH^-kwC)whf>6|uDGiOcfK3m|!o?AD zaMS}+J-m|zQ2w>f;H3u1j^iim1KG!Z#r5$Ezh-h;AO8(M%K5+k+UoK z%AQg{wJMm5gpT03&qP&7?_;F9Ztep)lTbMk2TS^ZDMRZP3b`#3P#QG3O(!5Az`p2# z{yUb=`G!5IHHmF^plXzZ7`ss?f}l~4%w{6(IrqKzdjFYd#(@eNU^CA|M{~zWz#1(Z zLV$&DT+yIDgeLJ_pYx+^_N{LC65(K!7O*37*wg4!9pC`dR6jWrUlh_DMd|=DupUgx zRsX`j-@9SDbWLh5xsT(czUJn>hhO{PFP4_y5=4Snco|b**1>hHP=yPDR44{+E*-jQ zGYis0#xcmiDV`04*#btKu@?ozH<~sqnsxfkv6peqp8$%?VpiWaPIkg7_a?tNX+jca zEScTMgsZWrX96L9+8D-FKN3$Q3ssMk&J1b}^~8fw8FGlb-`)RU!y@ji;_a~0S9F_gcdHN&&`f+^bpS=GG{ZbjcvEc9gf9`daTxDH2rzc@FM322454ov9 zJ`NTQum^$lZN}X*l2W@dQ zog(`AN_$vPZvxIZxc2?#zLtIA14TbCS3Yha@hxbXbb4D8y?|=bI7{#K25ftm=(^4h zMvgiL@v32sM?dH{=oAmF^+41-Du^ljW{TC-yba@o=DO|s5su~g#|YPBnth)mF!9MI zoYcd&zuu`b)h6K-_1cg8502mdwSW5Ro8z zz0oi|x=V50Ak&=khY$yy`NZDmYD>2Bb>lifiJYz|b(E4fbVj*;@=btR94PyN(Ww+>4d8|YW5(Ky!~Tj+Xynrs~9M<&xJ{jK%)KAz$( zzu^J@@Bi+r{MyjH*ErLpYi%pT$z~_*ah5dj>UFzn zsRdj^v1Vg`gIC?~if7 zu+H-^br8ekh#c4ZJ^47k`s42$zw^CT`#{`2!|xpU#QNO>FZl`NtPD)N^6d42E&8NM z_hbovwZ>bqyF&-y+<%7beKdU zp0l20pW9)7q_T6!+kKw#2-#E84x}WKL^UeLL!1xE73T?g4 z+kVFM>NKI2`ZufBUvTv?C+B8(#J>Un{_6U^7okfa#$!w%v>tXqFhv_1N8<2Fi4Q)N zRV3(maLN~4;)0JOel(KJL}L(#y!cA~1dtqT@--h%8gz?j*p(r9P@4`t8OR1-;uad3 zm50FTMy&`$$v@mOdcT9{)j2{6K`_Nap6bFe)2cmJsx_D zKTrN=|G%5#Fa4iyK7PJF1hhVqqHmI@4A6DC{=~87sqSGHQM7^&wIBg{16;5i>n5!I zSk$BIHy&8wA2natG~HCt{$A&e*#U zg=C4n$5*VW|L0zJb9~H~-93KhwLm`l3%_gNFVv44#+yGbvX=&zE8~1eYPo4mes4#r zkPlGQL%lE|xTs6w=rc_+#!g%<=EibP0D{E>E`MRBhxxot9?On%?B z=?jtiLlGTAZe@mEYSy_1mOUw3cwvJS@B`a*rK|!X7cSJ|@;bjfGSf}G_{6Ee&@l~w zb(xm)t`Bxv>K<|->OShACKC|0!NZq&m27(bCFi&WPuwId`!JA_)%~x$S9c!y@Bb0c z{>?;}<{$ILH}CVtyAS<*{l8VhJ1UycKwZOu2C&&RX0r^Mh7O!;D2DBuY=f6ZCmg&x zPvT|IstM1+)xl1ah?O_i@H9;sc3&_UcVEYKz8QVSw>Lz1Qg9wa5UIE9aNXJ`bvQ3Z zJIn2THEmHdrbH->^dOz=(WCLqFZ-jyGl6-UXsUBbWxE@EK7Uuo2fqK+@xOfdeaE}L zi?B=hw)iLY2J)Am|M2lkub&(j^-TVnwoIF|-!p2WneeOr8IPyxcwX$dwU*$pztR## zUbmnT7X)%@|A%kZ5#7Ysjq3>-J7c`T(G#9EeFd)u)k$Kxu#e*9y=ath@J<5CoAdiV z?|F4RxBl;d-~HaJKRV_SzsKRv*PH*#e@ZpYzRVYyB_(R&&q#aS&gXBBiLO-QbtPK4 zS6uJwB1qZSINLVkwv6l^o3<>#BKxJ78OLA)2X@s>3~mJwulxfqME0-oz2C!vS>tfd zrYpKEhaTl~9Z6_FmZ3;|)=uBL+g=l3`*ke9GBTfawa(O$1kpVS&@}sB0!ieIHP13Q zc}D%TSNOm5?#J(V!)IOnvsvq<`G~yaoopZetcQN+=KA^%(d4L6hYTqcD+!zkYPvs> zFJTxFN2?nN;TmsT0-m2}tDfvjKXH(xLepmE42Ui|`w1+6;gznR5xuN*oX6mR9nX^j zpB)=KY2sEMTDN){naSoq9X#Pi|FzD3v2=*>NgjO>Z?c^9#$Z_2>wv*O^VGb62@Q8f z+T-jnO`0$K9(!NSdp-}^pPZWy_?=hB=X}_`e~R2s{Ngo#w*RlxZ^JiUqeedHUB5oS-1D*b2{kFj${23Y9#Z>?u zOZu`zGng|6Cc1Zg9NCwXU+J66%NnFTae1D0RwS&v<9uxRZ6AdNJA)`V`e6!F&JirQ z8l&ad!>QkPaoFpd&nW;qU)$QDIwHU8U;0rhRelkU^DhdWv*a~f>+UpEJ8rEz0ZYDt zi{A99^&zhQtUUH3F(ORf#>c(q$w7*r^|h#2du-izjvu~x`qc-v;~tYo^;ZClzq$T4 z>SKP~h7c5j2O6DbuQ`PePO&2%4V=HYqba_+)p6z@I+O*4tN5V{O@QU@#c?6&EXGlaEkAEUE9=9VH5@$8gaEmM9egm63@i>>EA!0fmjhXVb|8?KHI|2x;m z-~OKK1OKvrzrO9qZ;n6qzx&PKg;52YB(yXrt%Z*Kon6@0jb$`??EagCWt11&|o{@dDPTb&|c2^%nT1G^w5NR4{RI` zrw+!sg7zzO`ZjPKSQDHL4&;SyEOm`Kpx82-1~yz7wIU5Aa!u~-{6k+wC2x88)pb=2 zEaM7(@W3Z4#(XIv``qynUU?Z)H%dSjiqIax#>e%e`}Th{be?-nKK$8l{-f7-AO7As zC?!hPUi69t7UFej7V+%}VZ%lQOpQMUm@iE?Pag(1sTG*^5}#h?M1Z=Yn-=pjea*9s z++KTv&ET{hL2BI1z0O3t+(AR{8sGh&4g(PVB;M;cWAiyrukG)C1&?Z=ZNszA(Om9K zvwKT=#$WDB;s!w&Bw*J^Jo$v%{nT0h@nk&nz3+S050d%qcaHb1Zx{d6uUsFm{%1GG zuRf@J`~G(wa`VpgUQ-X|%-Ljv3@A$3d%8}EZQ>J)z8r;Gc^T(bb2 zc~#QSAM5FSUf-+ENv7Cl!!3NuTFy*vJ^#`hovG`Q_W#NCdjo#|?>LU%Q$IN9=j;FK z_|ezg9IyFRh;jW>YFPJcufJs$F!S^TvEG((9%dX~TTD3P5ErgIuVV{7#Hl~HtfTW@ z&wu5pi29Ri+MKxL>#kTJ_<`B=UVJ@70u#4x5c7Hr`kzU>j!oeuI`(Kq@Eea{Jv%XVhcWXk++<^|4w}0{l|a! z@aJE>6mgGqb%~DzeA;*4-2ci~zv-8%lJ~kKWQp$$i4{j@7HXx=zBix?tga=FBk(nm z72K=**t;Qs;F@=eOXp9#d5QHch}o9;OqY54Y7$k=LCs~SV?6N_lZfbVdlRtiibpKG zaVS&AwK)n>dOJwn``0k@1l9t^1TLTm3C{6*4-ysFCbzdExZCPK^G2{L9{cP}HDHz} zPU6#_#+ReDUBE}zjEN0nco*Be*yfFA1N{a|p#e^H-I7#r#Nw(u4T|gil&AK|c4DDd zQKK)ZU$~Lo0Ufulvl3fYlCm{a&biOG=q1pvj8PTl?pq8eT$Cr>sFO1b9lY*K6FWXM zg?C6Y_6R#*^lzYf3F_`M&~{?zeQ{q{&Wzu54c(9tkwqDt`vI@hV7gqi$7za=pEwb; zV6$G>v}jx;nSZ32&MA1>p@5M;a{gQz{t}MQl09z;DJ|0^5UP}MWE6xbq#H<_v(1vfBas@Z+pqpt{&Cz zNH^t7bNl?M&wTJ}EBi+dgu>H+oh$`S=hUGaat0P64dN52dKdnY7qh`J<31dGR#j<+IwRXHFCnwx}eYc#}i+y$caeOcy7-!0D}wpIWNABD|^~Q&~lTWJd3#iPwf2HwkF}7MCUc6Q10)9xCQ+n$Nz}*XO4Uq;mqUWJp1*^PYI5sThX! zIX>$Utbqh{y&VS@Tx;KCs~jv~^(DfE1giZ3RKl!L=u7*Fz}Dk1*l=CKlgY_%+iykd zF1-7Vddo2St(vkwbKE?KA3ScCYBYfMX+FoLpIzT={q}h{#k%DkzwOT@JM`>V>T~(6 z-}J0)jtR%9{{@N<`0%!@*-66jK>;rC;cDHde$ZXF@qqxA{N9g_H!M7SU4U)Rk91|* z&AaYin|BPm-jQSHM9i?IvtnwUuB+EoKVw=z`lYzsgXaOfI=-&{{{N%md!+H6zYcg0 zu10=SY3UCDd4i2{#*DGsulLP~@V-tBQKl|rP7F%_&j+&^^YKLGVt4yE*<3u~A1|B< zk?!802u$d<&VFD-Odqh|YiustC?>}6g~*t>9LK6W2qlGqL=gL#$F`wGy+wAxa}}vN9NJ zFG(svMDaYA&#B5bW^>p`A5jb!N5zwV3Jspsmp%0Y0&I7GiW!VG^SO@hoR`D{%emw8 z>s5!}qR_m$sE@NeU%04S`ON_fdo8PC9N6(Iyzu6)f+reK@j^DmHiH~)5Mtm->`m$x zYUnQf#$ZGSGk8$HE4vdUHua7DaeNC1pT;(Cdf^?lp>NVRY+iSN1}`N=0L{rF)`8S) z#tT_@8hhw{2t(=}jh)Ycc!?2V*OJ|0;|h?j=ll+B)=&mY>3U3`zn7u6eW z#oIb{q~LzSx}I}`r8<3OTxzc|e0d=cZ+NgqY~rc6*06)7WQ!-su+}`5CEjr; zmv)D{{C?q!jhNQ% ztMe8}IE`wwFuW(80Rjh4$`CC$#|KzT%WLACr#86Iwj*G^l)5Y+#U=lgULLz$y`a9& zjL8$W(Gc}!q)#3p8=sA-tkA&zSDu|0-5)VS&W;;@5Dr@VmNaF3=*jPSyud%Hd=TAZ zHrIO(*l>N=7d`Y1RnCVE3)(#d$*#5K$q&=$7-1=JZ_MDnx4dNSjR}7_=5#p#gIBX0 zfMkiD9Gq^f6M_B`SL;ZE7_4XT29W$3yH7<<-DRG~5f!Cte2d!hp|6xe(Ta^UG9=#? z*Y!K`5;Mef+Q}r^3kKG+^)I}8{T-fi1I&gP(B`QQ+E_0@sTtOgIk<-2mq(}{5ugOD zbJB?0X0w4AowDT+J>d%^oOSNN9lzB;E#p>b^R&wFng~ncwa)Vv{fD{xvE^|zhbg?x zyX;`XyCh|v4psfpJrRLpJ->)iJ&8`9=w9)Kb-lqQE~Da%D`R-}JiuS%DB~r2%2@R% z>x|!VBfqeZsKaF0$KYwMn~ycmZWuA{8ZP00ar@@bX^t~fDE&wK84pWAMxjnV6ccb^ z{};O!r+e4Y6G65mjf>5T*rGc!yKu>08m5@lG2+&G&*y)7qc5U#0p~=0EDI8ZK9gN& zL1IF2oGb1d>$m@XIBbvhdQ9H|0O|GB@%;Krm*oQh3n<^%Xr&+Pst7f9r{qVS_!h>n zr}DWxVAl1%%t;T={Dy)|88wQ6{=~KHdy&i(7I=b@`+XoQ#V8|_6}Qd>7xoym55bz7vM?D3^cs8hAIBZOs3Yg z;gTPI#W*qq5pe1g9C)$`*gO_6!Y$N>#vu;2rLX8`63U$wYpX^43?)SK_={>MdKZ4bQM?01TX|7pz?Kj-XW!EV+cW zqR!`afx;zxb~Mp77Id#~&xbyWvErA%my#|x;U75hT6Wi!tm4XQjHy2sJpak-21R}2 zTwK3SIAL(9J^t`woHexWDId!0xbABhDq6z0#pL2z{#jqXD?3FxIiqN1|7#iDjWyAD z{oN6bY#wPbx3_2A0KKjy(t#Yh-fUc1!2}xi(zG6AGp2?d_bHtOoK=@4BvatX598bq z^Grd~rE@vrY9|YtwYQCZWxD~$;r^B>E%|Do|Qe*k#Wdq40kZ~o;s)sN1& zdABqsazLm{1!o_+pcw217E?Vbu?o`!AV%x<+MP8b_luC~2zrkEz~YI5E2HKkE5O9L z^Vu&fGfxc0B5zJgb#^uJGdxd%dVO11W> z6+2%tM1RX0j?6SV$&O3z>_ndS^Ep2Jh@qdsypa%pSBfh*%!LhGtq8AmX-nkj4B7`7{&N`Cf^_z^_C z&{VPGJk`pO=m`!fS`Lj{QUdD6K+v4uu(B_VtURHKPR5Wzp5TK^3IxtJ7ZF+tg@5NI zzw2u*=rCDaS(DH=`rLreCB}j=L7K@UTj$Tgnb1Vk8@upz0&8-rui}K02Kb}3vtAu< z{4GyDzU7yw_|e}w{?UgV2mWt>D(WN8B1~t8igH1<7*DWdOZrB}v5XzpFvX>@dBUW> z(KWU#d4^?6pe10)G2q%5=k4@{dDq5{J8t9`?S2nW+joNt89eSla9f_1-EjgAcn+8| z7BPI|APr<|3KXN=y${_W^VFJra}2^92U(nYJyALW;Ci^OOd4*z1FTv2V`n{B*wOJJ zw&Bs#F=Cqz#7-rlIe-0*VDGNW=8n!f;|bpl6M}jxb!SIEy}$r98m-I7U`AgizVrm9 zCKj)ck<8_byC+K18pK+63c*=$L;`QaJ20^3nYEQMeI7X1=>plVa-vRLsk?QY_y`+~ zLyS!rSjMytA56fx9L3BAd!qLu9>%)B+1orPhtrN>u1dxN0H7*=j8R0heE`^h;u|>3 z0&8pN9G)zVoBZ%$sZoyT8h8iT5WcP>z%(TM5LDouZ=B~aIbcoGb%nOuWxb%^uX7!E zvrV2AeKI3aU1z-QDrO>??6kUo3Bk-xpFUjd+hhFK|4H$fzXO24`V;%t)bNq6w+qfE z`F=s1JA~R!-@;Hy{(J*KJ#rtD-tetI;|cG$<|j?vwg6k!4Ju4vMMEah4FLuO26oQt zw&E2s`T}HKyP^5zj=yzHeFHR~fp6U4^9LRgj<6^liD1d9#{@v1jT-765F}dvl|QLA zyw;a^5wc#vHT!VG1QL?wh>zrQuki|KS$+OePW&mNHDZFR=`#s`+-28)G>mg*0uv6q z;&doxU9l_f$^xUav%A09|BS5@e*RbeVNmIwKQ-ru5i3fW7Y*1ksoy^Qose%4Z!(f`C57JxUTmv(n{ zg|UA1Q2?6jmeYtlv9S^pa-gB&0Lb&R@#}Z&T;%z@PK{I^-pNVY@&lrCQ4{Cnz7!xj z+W{$*WMIuEM1+s4x5|1);KV9`n zpX)r=2eQgjG5b~tU-v(_5Jn!!Ytem5LgcK+{9!=` z7@>!eL=op@bjG{urJVtlvBvJlh35km_ywSG?i(ZLPkE>leBfR#7T1<`ml@YmpKWv) zm_LYwH<0k8UZ?MUA_w@RtHfcNYxITfjCu5B5QxG|{7?0o?2a(Ok|M&*kXi zjH`sHODINi+WAsM8HgPY;b4U$xJ}pKcQZUN7&nLa+LP|{ovSyz&y$ZAzGeqJiuIoA zQG^KclrMVddB@H5M{6aT)YtWIY&oz%vmb7G3Q2?F?;Q&aP()BlLt9pk*~)I+&+oQWuW1D0~l}`c6a}8+!kcuCe z*+&8)T@T2?f7`W$8OR|)X;h7kUC3N#oXP8kjye+502-1e-q1XzI*a5sJb1&I92~t5 zBW`$?`iGgb=IS!G`bDnoXs|~)OgUjJq0)>u#!=Syi8D`>{sDNU(S56v_Ij3je}kS;7T65I}U~PpF9ePA3TC9_|~7mVk4jT zGiia7eH!BgALCVcn`<)i$eMZ#@$@V>h%0WkdktIu8I$wbc=VTk1y`;uuvU z_(;=sBF4?mU`BofU#tCtKS3sf5$N9h{A06ODT_EjRd{;Dqc;5yC* zx2gA|;{!~d#=Bqcb9j*l^Nz=1#N`CC*Q-r`>kH1plpm19kpnJYc>a*7`{(mee%S>a z^(QiRjX4&KVxavs@ViA~YaQ~!Ie}q>UOQ*qvCnk~E_Cd`fie5N?@!~Hqhg(`@is(N z#WnQ_;xdxYiq4cFX%)d$&0ET--sresWkCstF#DC_R}EnwgrR|BZQi_vN1tVPR{g>|5m=!+SnQ_AFelbDP(f+2pzt;x z5Uvz1bI_XCO&v4^tpCER50^7<6yppScXjpa@BifEML!+aV;mp-uLItQzx>Z#Jy=R# zFq=`?hrpdI z>N3(XVWxC+?e*&vSN%%Q{-}}Zg!@qmq}RY!fC-$7p%XKYV&Dj&?Sw4UI2@Us|x;8-xn;ZMI}L3e;ddR;h6mC5OcUEXv4vKwxK9uS)c zjNt+`HjH^N?<)uxKY84?g-k>&)jQOnzZ*6LsA=UhvaTtM}r^c|Gp$ z03hGhovW|9zI*erJkVIP#L+yRbQKOfHyV=!7@q+yT+QR2ble7PyZJg!G*ccKaK3N> zj^2)+KR|Qe_(BE0Er}cHy)$+Uf7uzNLyA1%a6+#2LWl(Mn$P*to*Z=@6zEQc(J%fw zN)-v8c)~jREaLPFJW8DiC-#t^J>K$qvg+*OY;N5xVB>WFvI^oiv8MH;mjaDFN{%F8zQLw&Wiy zjbwaoh@;1aoa2Jj*!8BK3TFHyfSd;M{8#Asma6d3kGOsRVWeH@fZzN(F9WvW78JjYZz>Y7Hz;0!|4(DWGxYmv)xA-0J`bTe6YcdR0F;D^3Q&Ix zP`K)0kPOk5z7Sov&?5nC4wq&ug3+|@otbm;U^d~nYzJWiFoUO@tL|u`7&goMPc z6_%fU@!FN62lFExNxtOCI=%I-tx1uh=<$%+S+SsWVQLx3jl!@o5R&+Fq~c>Ax?qVF zyb_R_6lHshAGj{Q^QW)jwa_N=BtkbkYiE%>YDnaVW?8oWN)xT@h0)0#{FbK5w9ct? zV9Lrbm&0(z25+LMlFD&M|G=#$Q<2x)${ncz82J`+!^5apX!2z`#+Q{fr&y#bSYr`V z3reVI`U5kJ;+S@yfnrEci8Y=vF$hM|JXctA*QE;7O%f}zrVO3(qt`*u2V@BVpDOn~ zATr4|l|J|j$6DcRLb-EC?WsRDj@BPu*>D#T+`KrM54eswJaE~o5&HFpjdk8i zm<2c2Kln5Q7MEqRPSmP;!y=4;!eVX-GDjD!i>LfLzdFN&kAz+VLlG6v{VzK;L>TO3 zVnrRL81H+8T&G`~OTy{uA#IWaR)99CQ9iN5>)O66_ByF{+T-wt` zF;R>QC&nbA1~7tmT(x@6)1G$qM7{y=_GNIv#k=gU3UkRz=;X9YujcWb3j? z*~u=%^`IfRcxX5^feQ}L#ik;#;t|0-;B@#N7hO9~QnL4=t9xCoPs{Lng@nw-JVk;f zuH;QV+RL9hg~D9{v8OLthp^Wn90Z)TKLTJyz80K32}~xf_xP;GevmG~J%Sazi!8Qd zsuMn3jfyE-wCFQ#4K{gS2F4?Q|gYcWXpQ39{R1+{p)r1r;}ZtB)q*g zkQFx-Ta#MUf9X@#YdmzZS0OCmvW|VGMAEV|4T$T%0kb{4z~VA5r*-Rk5kIYw9lVx} z*~KduiY>&s{|>V-Wq~dHLq8<69utO-LQG|;Ay)l`2RHS=GxtSHSnCo_^9gT*@)whZ zj(#R0qX4Zp$(@%dZcOm5#Jow6`1HHi*r&o~J@%mqlp=jCF#oZ#8!-ANeEP!INlSta z;TYLd&)rb-8@vw`S4P*%cr1rd&XFCDt^+GcTJ0uSa7$b*csbasy-t`>4-3QCI&Ft- zx{{BuqINqYQC!52Ojtq%@-SDg^}(f<&7;N+!+iP_D_+>i*#cB&^ywogn0eiO($(>t zH)i!XM`d`N!3lfH7e4sSRl{-g4%~SihQ~gR4W3GvreN$oVt$Vl?aQQjJlPMp zae;?AVZBi;K%R5`U>FC6JTjRw`Nxtuop?EpjEe%{=X{bf4w@O)z7z*(${9M0D@c*C zbCjvKKfZ)URocGGJqpblu>7xO45`h8i3E7xlNuA2AwP~2nAa4$*!?sGiZuA zX@|TCJ55O#{Qi7^bH_4(F9)dAUI@bF<>-rT@e?$~g(rbt8`f>f8Y5Dq+q<@2*QDph zYpuwk8;o@s&-ytZ(J4_t-(Al|ALvewC|3Mn_d59W$$$liMbQ8X7<~)CHs%*^-#fhm z$NtC>y<`6qIgqhvbQ~7eMSIO9X$X_v3GbMMH8KWMhR<*=$4z|5rZ7Lh+{fnZfZ%0F zy=mmA@)q30!+e0%WY3dz^Y=+@0#35sac8aVuUcYInscH)f5{l#T2JBKA0!SMGtB#S zDFMw3^tgy-K;==OoHfr9Bd((Omb*{CdWu$$|Neyj5n$3@-8sIv{z2V`Qe_#l(ftDM z!Y>_saipyk;8HGSjbf3H>95LP36k>cYGjacOyg-WhxXC6$xagdh z(Q(!*ILL&T(%?*0s$4Hou%2;bvLJBjO69ehri0%+=FNFwEH#-ag%4uVaXI7WB(nm< zPq^f_S;Yfi2L9u#(b(>bup}W4@bGMH>3!*s4f8h^{Jz4MwaD-$JR;*$|7xX#98i~dCwv(U3Ap=|e;7Bk zRHlRytwl`1jsDrc0LB}w)FA(gm*>1bYGN&cW7pM z-;#G2=^z#}>EWzdx({s;j@UqJ9J&O=?n`q(vPT1~xs+qY!6%GQU=<@y;gXN5x?$}C zNZb46B(oneeMP1X8%^5YBlC4|CRJ4hGDl3%TMyRjO5)-;i(msTGlK)?9s^s7Jmg#P zmHRax@kfpqE;%0OVwUzeDHQgUXFl{9*LSb~rdFY4wPUlq)aGK-gLA!Bz(&+OO=d&v z!!QnqjMzwAi39Vc%juO2fEfm7^C)`c??^hhn((Lt%jBn?G7tyaGH~ufG>3z9(@loK zv#tX?$FI2PX$25eL5u@Q8rqGMua^OWc8;3_1On3>2fNgae66SQ&T*j|<61|E(~p50 z+_2>wHO_)=T}MQOgJcq(_OOt$2M!po%?27^I?k|Q?^OpdgMY36()kl5U2==LLi5c!uS8SIs z@O6DEV~}Kg(PU6&2}{xok6Oa&-JiBey1_4?eprwwb z0`~fxcIIJ78P?D=$^kV5N6U$~@t;{g`u9^u)Z?H1ru-EE)8GHVmmb#-eM+5zR+(pb zZ;W>$FG#a&ZsO<|UEQpS5st(Mo-z4mUd-EXo*X>p47e7Jvn{#<$;kY`dpk46j}h80 zJ%Qm%Jm$DkXY%#IYe5z+xVp&vHf%%q`UwRd2_mweAc-q3WJvz*qluDz@ET#-mRTIZ zf|{J>O?vqUikv3y{OwkP(MPb>RenM$u|t%rpUrHWZSg(*6HNeFrBHo7TX^VbrV;3T3f)c_%f zmaM_8=b3Pbg->I>sZ79Ay@eDu3MR05YZ%Yhz+jxOA|_8ZiYw?U>m(@Q>Ua5)&W>%# z!emp&1XC}eWk$zX|DKC$sn zeBp!NQ4D`9EIQ6;xYC^Z6d*=7WH$BOjSvXd$PS~|n|bpx1vxiIHUZ&q^?{4S_Kw~1 z(2m=FFowgkbR-TFO?l`EPhj>(cGur=<~h+R-^Kp3P$g&@=RCA=$tlko*i~+L zkj9kKGR}7Bo!9-u2sq~{!mVfYC3(UkKvqrTNod+0J_mGMCb!ieT~Ystcx4Q%^Y{7A zJ_s>zLjY`8am=|fu=io&LypwD?=yV!m3+a^KFsN7;&`O%ykGG2@%OYqQf^r zw?13A)A#;9(*F0ssZ@g-3iAAub*>YZD5Q5b*b}{|K<;y$v5SNE!R!Rd`^bHZB4pGh zUN7J-L$cV~L-J5QKxrfpj8o)-gUf`b*Zamr{92I1kO&#-%1&t=KKVu-;jX^(<{4KX z65kUYfAhWr03~0H#K;d|BP>$a4iZhutF{w&{Y0N3bjm_2r8 zt{djb;1fItI5xKssG86DM$aG+}Ova6HwZ4k70JphNYF z^gSEVxs+J@@7fsXz8T+Pf>*M{iAe02Cy(qAHvEC?=Q((d?5AszMGWWjZ$ah8EcGYf zj*p+50J;CmFQZ}Jt$z1eTIRkwFO$RDnFCb|Y>qdh)pwNGAWMkuyC+hGEMZU@?z0+T zkNhjXqSi1ZB0>I?9zC(AU;OhaVgtB!|6O+S6h7SWM0a%L+(I;|XFW7XGk=XU(wCpq zMIe0gaW(C~1(*+oD=v8L6wgP6wof$0Eu&c+qydn{UIuSh+ru}dXYl_|-n+;Cx@~7& zzu!9hoFkW>3baUsNF>$}5{-diD+r}6wJjuAuF*e8EfHx|s-guH#ez|8=hB`F7tyv7 zjfTq2#Kgp;^&d@}iZLW529j0{;nG4Hz{1&U@4c4e8RPkkG3R{0-@SL~zOCJNt?xVM z9OD_!c*dCXeSg2T_qx!}jW8C%DTe*3;=<-eF$$5Fo9b0Oj-JujR#J@U>HZf>=BrvB zAD+Z-xPQ&|w_h`oTVw-m}v;`jWV)y!&OIa}9kp zDOOCn-!`x>ZHKVN+~9m@3U64`O&;^bpjp>*IS3WO!4Thu*GdLoC(j%;jzj<>2M4Kn zeXv+hf2x9trkda|o(DqdGX{Zz$QU@uONon4_G$76TvuTYCZ#loyZWo~ctJQ;k3mLS z7!MkC8P+{(yX(o`G)R*Y&^WI&qL#^ zA*%L+w4`C$AsrxeM z0!YW$BBgQ2@R!vv7m9uo)b_|C#KsltvrYiYzG5%97Eq|cMm^GOJ@vFZQGl@Lex|wV zY#h8nk{Te6#UNv5{x8EBbpcgZaw~s)lp?wFR%;rg^T#!_NzX5AfO$8Av(V(v zeF=Wn=+5UgpewiXrLMk#UT}{OKlpP$^6=-r4{>k7_?G-B0CarEZ+LwAfyc+sWFw>b zDsU@O9gB|#!m>fxBm&d~H;$$Xto>w9J9wEmtU4zwK0Ccb+=5^B^exz$x<8%1C+Q|8YiAK2>aJRqu;Q?@&dqoIDQl-sZPkA}G$fmKS$M|g zt^DXoNvl2Fi_DZEe$!O&a<43rv~~4lL76m2EU%J~JjY;Co!Cs+{ICTC4#{T!FF423 zPthi|c{pd{Sjz7@-SXxq{dKhNc1R!!r<~d60@D9Z7<%<1)wmz3RP|L~%BARGPejFm z6JWWzPSwBKBS-bd8bul(`azD;#A+eXRNzbABFYwM3gNi{a%7zVTvy|ixoXe)l`k&# zyH=S#1C1^W&KU3S|43Wl>voh`g~Vr6f-Xz%59V`ppOvl7K=o&I)jr6o3wst7>#ny2 zI6l$K%{muLP8Ft$u~y1sBmK636SvhDPIOj1T9=+R{b1BL|4<(m71WvebSoOr$kh0m z@B605r>o(|I)6+53qXqbz=!_u<7-cUXB7Aox6afydsX0oCwj zLysNve*sHC_H|F+yy((K=mM7fvA_-=I`TlIJ}1T@+rqQfV`O;YjV}c53whERx2Z3p zlF$zyIyXekSYbIGDS!}MW<(8~~)Wl1xNwvv?&Rpnr z>2X{RNP)|ka zUO?hIk6rNPQ@Pbykt@HL`X4U}!dyo`vRBq4YfWXHK58xv!KF`YgI2fjHoM^!I68$GOufFe z-dRrkDxi=DF9)aSXJ4%QvQJ@19>=xcb#)EqV*sbH#KbLm0L0j_={R&62WEYNPL07q zqUJSEvmd;pwz3HT06+jqL_t&tlG)^${>TSi@dtRpq&i^iA z>cS2W>l(r7JpyNXVnI5sH=ouRigp9wYK#bO;A94?d0o~?F#F4T+sB|?b&E{lG4A_M z^01Tef*XuH|NCk|zZ0eCpN1 zAC15H@9PKo*3910{{?`gCm(qDcx-O`bJS6Yi>ZP@)VTU(QRDLy<W(l~r(i7xU*7hZ+v+QyY9y~+@uuqRGqPSRPvRI%!ghcZC=~4Y*(#s)AumVSY=>JhU}iGCPrm?wLco?kT-kf=f#!m)^<>~m z5P-adtPAQ}C?R$}ub&ZR5)D2FC%(0>^)F#evo$wp(}ev-{mPrUO{DzYXOpIlL~n9b zheTamC7_nK&tG-l{fVL#v483$C8s3c&{0{G7^lv=CD=xP!S>FJGd}oR_uAMD5|PPB zBc<}i2hX77le4bo$1uROls~2pYyD+P%$lQu@}3fE7I*I}&mZ>AZ%J8yV39F+0oD%; zMk1myho5B>pq#oC()l%)@wlk>%xsDx$=ucv@$fJfW%)awV|sn$t#eiH$K0<>7>xC^ z(3v2KmS|`7un0_y%%XDoT+j~zyiJJ}hWfj$Ns#X2CUkt-ACm~qJVNH4CSxoF(jFi0 z|HP%sx58(SBBp+XOVq-~1%J>#d+DWzkC*kWy_4guWev7p@u`>pOqBA~N$f1S&tb>| z5F_iv+__~l+!5k{cKlg|n<%qF71vmTv%MzXY+7hLa?pJ?WF?gSLRvx`ow0Q*yF`>8 z<2v5{B|_6ycfnA~Rt695sW%pcJvXgT0yckD_5j=l-5$N!D$=YJU$eUJxH z>a>74Cl*w|l8^#Q#b`Nj2%{kDAG`_SO?-4wQe?XUTun{C({!V|{+3mfws)NEN~i>G zWaAJdm<80}yKS61U>#5Wov&$}uXs(9Xy!{uPTL-np39>}mC=*QFF;(bWA?So1UCMx ze~1aF+}^L@YXOOCKH}}Zw{LBS#x-iW)oK-ux1TWTiC^I*a<=b$&fz68Dv1z&5q49* zHCe*ahp_bweJLAXu@@ci<*JSpX2vy8PgIj}fI28MpEV%b$Ji zn;(Dmihrx-Z~gB9u(A(4dGfK>p1+pg0CWTGJJ%Gm7B8FHmo0Q3JI-riXk5;35D40F z0`=uhiWtsSvaK9`P)WxIu7s7p5Nvy&9>)_0k0jjEbjI_-lfbG2aVt|76lv{mm~~|` zb1bU@@t_yfA7k@cU-MP`k zn*kTf}-2N42S)cI{^ z-7la^Jjy6!dXt_$x%PW#GvOY|2ODe2)7+&z2(u4KOQ7cj9w-t$#_kQ7wxMH}35J0^4+Hkv;(V0E86+@^W6V zFXyU48%O~zzxq;1DzyNhNh`nR>;C6DkTsgNhQ7C)w%o?yZu}%lmvYoq%DVnGTX7H+ z_N-uZrau#bnYy84ENrbbCqnsijZO!&e%2n(p>a)Eh|HJM)e+hWaK2tQG5Dhv>m21B zuc3sx9+G9?+$Pr4Aw8vzDC&7wKgMf(xiS8TcTmgo$tJHC+zx$F|wi}sFqwLDQ z`g0z)u2Vs=1_Qq9vLU}wOf1NWk$EnjH{&k-09k!$Ht*xDuS>$r*PmE)P)&pBd*WCB zUj*}8J-%)K1wcaM8?}$dW`9Q)NZ*bssJYq}aTmi8a4dmiz8o+d?k)!ebL0CU7NeHZ zj-Qb@#?i~hS3LHz4o@9jqP5Y^=cCYh4n1=?=u~lB@TSIo_Wzo{0>mmMt=nl>PyWKe zI{^_KG2|`Q_0Eg8;?V(K4@he0ge4%OLfCxcANF#Yy!zKhVda6RHj2}e5eN$W7{2uUhKSxdL3kfvPN&d;jBsiXWkh01Np?wiw7kjy9GFM z>~d6#EOCQ#1E!!G`b=<*DT}s4GpR^R;92kWYBl^7Elb&RkZ~2fEGtXllUGw+K4-O< zaA=z@0Htr3h^f)~3bnXOY4OCIe`vE z_Qp9$uY0mGEb)jkuDY;d%fdOwL%md`wUEMz5`XVIfx^UR{#Qh-;wLhvD`69l<8=P| zO1wRGOuj4qTg3TnmEmv`IeY4Yg+H_Hz2x{7+VkIr{8Nd4%hDsgloCHpw zOZ_sgpIGK)f|zHyhPd<$5iR>U91);Ub21j^j!&O><1&3rthdZ_Z@`$Ct@_9ZyuKhi zNd$~uqK&L(VT`ft+WXr7vLs+>!tDQ{8$N`Xx$r9UaP(4>TUP;;y3=cZXFs8@y^mNM zuK3EOzE$s>dy}zd#9w-{IpMC@uswPBfnW2B9^&`Xy?xgv?d?eOD?j!0x4!o9?33aq zS+{@*j#GgBz)m;oIsmnSvVn)T4_$7Y{DnB}b2=+h8_cCy^U1gv*zB9Ufy15$Cn@u` zq+7o@k}=|z{AIN+>sQ`IhOHBqeaZahRCuLML-V^YM)k0!zvNjBbS458`r+~Hb^8>U z&S#y?2B|loan39G2{A6?G-tmZFz2KM!9Thz)WhUC?E5lQuzw}sjI*r7DU`h6Mpue% zc5vO)?h6n%Q=0qvI{Q-Ikqup*v#X%XIot3hpeU1I^hm7edjCo6k$&c~ zfHhqcgr)1ZHtH=;R|=0JhMGrtvSjc(0#)dMB+T-2z0 z=eJ3XG&GU+T(>9?>W>(?(_iMU(8YhUYEZk@r_brD`3wJGUa zPS_WH*~Y*y0)tm$UKqUW^KbjO-S;s}ykq4`;W4P@>Z66a)&c}F>(WrX8Jlq;sjFv!Q!SA8)1R_B3h^6q@?MDDY(^h;RwzlFy{5#*IU z=en&%IpVsS%R+zh944c&1fV;{>OXO%x0z*LuHNsqnef2X6QE}~W{(d){P{0Ed~1ii zO_Pg+w#y@6Cg{CLlYV_Zl3BTnFsUTn&R)K@lpRWN5&CU|`q&E|3T= zqB;m-dE`E}qniGtaX1I{&EHm~Wy+BZTn z*S1hx1(H88z7?(g7BTz*3c%3qxO#A=E>RBF33Axu_Cmr}?qzRbA#UYTzFM(^i+n9TR`PmGidHOaNB+aOSwDOoM$@@x|K%xSU1cf&~ly= zvEr+k5wP2vvHB5pq(2gByq^EUUpb0@&fig&1rb-c>PzJt9h!kt|1}@p`?!p2-G!rX zXMc7UV`Ctn8m_$8`tQ`~a!2RXFAdlIzolSo=q7M@Z(yu*?UUO*V9uwi60k4V(?)bh z{i)mj5o9DJ;EQl{!dv#Ne@VU29eT`j>g#~h5Ae{L%eWD@J&)#aeObv-PSx@FyW>~? z{|Oo1uCbKAUF_!lRsZGl&w2Xyp8h~|MqzoN zV3TLRDmM(fub9MHem$tVSht@7?1u#$aoCGvRvh4d5sd5R>{Q$7L01D>=NsoI@b*Z) z(H9mO-OfvX`h=s~-jhs}yuKA(`RQ9HIAlSK`5vCWHjn5tACX>$E%RGm^CP!oPJPAG z_@-TONsI$R*5t1Ww*Dq$@GH%k?@iY~X>&$d&8Ku27wnkOgI@Hze;u=b0p+os`V2I2 zvT5!Yrr4xuzJMBUeWR!Bz0Z><1zmZ~;{hJ(zf*pqQ(m0wj3FRAaO8yc7>6!+FZH9N z`I?~Vn%`Ir8$1BFFonZo-l2DYige@4z_RCKyzxU&``^!15Gd1GU)LY|f)X>=(A=}% zawN708s)e$^$O){jHz! zp@)C`Z~no@xB74Xy`*L*FOIj`@Kv9F`FA{j_WbwX;yoMBcfLLX+s4+06iaWotI$U2 z;#l@+qe|~zMc1~SxzooB#K3!eJz z$>-b6T8p?_r6v8Rj*eq8vdvt>yr>HZyz3-OILb$%AXyJ>dR!2wl}|PvP@=)1f9e_D zbq0R5t#kT$!G%G#JT5VrJcX=#=@Z|2jw#YfWF;d+Yo|9H7=S0XaMCXtyWCp_~2ghr@Y^Ll?Y_2N0t$)a%2zc=!Io zw*YdAp0Q8o(g$EkgsEbjrxQ4SXq=~_24+AQ_$QwKq#yb_FMoe@;it2qr1kzy zA8_0qkzFlqKFsVa4icDe-Ow@-Xg>0K$NCFfZz1>s4xjBBGS&p>X)|^w>IcVb=K*yd zpr$vRGKm)5mLA7}Z+^=@dElUZ;CTR{o%*p9ArI`S|AIdRcb=GN&KFiKYQ5J-o~y3X zv*|YnN;Pi%yy0K5nZF-stwKu;1M7tIpeN3VoAoDPDoLodP(OK&c12GR;En7&HCg1C zR(LjjnL<-x7uIo;r!44lSQFmTl@UvT)^k3bAqLNivJ0LJnt|zlf?MPXll3p0OZp-_ z@MWBRJ^NRLBVg(zvIsX_a#?WWt!ehxfPtD2fnIt5eW_>l2dMR9Cvc}Ld5e!J*;)75 zX} zst)v3y2^)s!e6((_$Plq{{s&{=Wl%U@kc7j+j~D+_VymquK+ zw)D7-Ee_E%^j27Ign^AS!!O#_(W ztp|kcWZ$KO=+XI=)6eZCpz|}aUUZ%h$iR+Y;dY%hnf-4^$|8O=&a0$s;OD`Uoj7=B zUz%yc0}TG~_H(}4Z(_~i_IDiEQMoc{{zmnSf#{fepA}h`<6QweP2RQswBaD!;~jI? z0er)0VQK6?YsuNL$!0@7_FV}s(eJjX9G$}zam%8nV-WxOys;sT3Xta4zDQJD)Baj-_t3Z%vB}wx4eR$$ zD=@ASH6ITOECD|waA|CxC%tY^_4}+7-0VsRcyj7;GVfP)Z(_R6HaWf(E^Cqtd*MS- z5v@?DpFDZ^ZLfUn@e{1y?(uE^QvhoLKjSBV_>aWl`>Q$-eJEByHgwvenLcV;ee~$p zLzE~SaH!$=DLhfQ8PELM@byP!2`=qCyPvttf9P)*`BS9=xH5S7I-vaMIn1pICbK{q zBfK#UshvLaFEFNRS~hORG})&7?e{coG1rw3nv%q|+H)^uumJQXP&Z@-L@?^bvG!i` zjt_8hXU^D_7yNHoZ+!a^o&La(F%6n;wX=a@I7rR-eLaSk?nEYjW;YhOxoHXupK zS5Ff0jCnd!q$~8Jn3!?S0f z-ZPdA+A^YS*G|Nx!<93y+5Ft8@E0nfdGp!8-G>F>9+&$s zQ~}HEJN)c_uRE@R)o8s<8 zzS0kX_i*CZ)j1O5?fTDt^z$t}3W2Y~BR*{QhPC)`Q~&Tj{G0JR|38EOofvmT z??A?1|0kb+=x_h^m;Z94`p2%x%aRRKGp~S6ArD;cU*a8a$K`=>H2X9U@J1Uu2Ez8^ zfaF0=2)JD+8@}-iY8V?o`u6<9cfji2cviUPK&R{%2VutF?Ni_c{ZZEk?~*5ZuzO@!WZJ|zaJ}B}(J9z`Lootj ztTFM{P<6Pki!LFDm%NTQPW9(>iR-B*OIX{BxZ;ZL?)_f%&BQ|`u`Y87i78dIy!Eyi#>x7H$TRivbzhL3f znUeF)g&f?khZP1qIH_h{97mmHjJxfPcD=E#c(2jz#_rt8kHvTmVZutf6NVjZw*Sq< zH8FieZ{?lm6kzEZlyw^34fOt3JqyOd`@JUN&maEZpZgC#e8Km9)8kVu->GX2H4a@a#X&cItMj*!w&HcHH=0ZjFAuLP%5zh(GgV2h9Pv9LzqFh2%i2U-&jP z*2w{#Bi)%2-g&@7LSJINOsju3Xn^fJc-J~0-bdYi1NJfL<*)<@BT!uZAZLEmjlUBd z^()pCn$ATU3b*H4zoM&Wg5baEsTUhaa-!e#J>YLcPSn)eVaeKJ)1X@R$PE)5t1eOQ z=u9G1*U_~}cz}n$DuJIiRsH1?+w9la%3gdu*JQa?UTM7dJdb|#*kVEK2h`^`Jg1*} z&pL@e>%-1Cddf2VuHOUo38i`Or~D?-V0g~TY$q_5mwGF5@<%{iv;Vc8I%}WbDCl}G{XhXq-R2hj_z?f^|6hCM#YKH z;Pj)3E_`JWPjUsa(ii_3mp-Q{R;l-4ksUoA(JA>dHJ_%-wdPN=>+7;R-U>AM5^d|s zykU?rKIBK1Lzba{sZCQ~Yn)80zDivgt9k``9n<2fe!^p8%BmF3TZ`c@^48sj7#9u| zmD$o1$&^p#G8S*cZI(5!nB-jJ@{up?F(y@}(JU?k8lij%NGJQBXko!ef~|ffw41(Z z%z*Hz$Iy0M`!jUJdC9)4^%rN!kS14=5v3releW^^lpx)*ytoCfWS2g>)PMvj7y0B9 zwmvmk`;=q?W5iUUd~DAfI@3g7yGZis6`qy!q+kgh%xIwc(?kEO)k+T zwQA2v zg!LrjO(H);4g){>!(yWb`gg{;;Q<|nq%?n9m-^Ed{^Y&vUuhh9X6XJ~@Hqr5`67H` zyM#P16#~EWyCrLkaL!sG5X*i7r7Lq2VL}+vH~nkw;7M95%T*fCSE*Y`=fS>@r>xFn zm{`fDvFpIm{t6H#ub5<9_rE;`Sg%k8tgus%^|KM3pZbm0Im--AQ(e+28#`$XalVqX zlv9QPfgeQGpY|{|&jK8M6%`La0?}h@46eWHt+l|-n_%n}+587@*Xaa>3u~pfhRV9} z#{&6jx6?!R&y4FxMnk0upH+SLdtctgWXw?OcYW)D7Gj zzhE^bPoJyCZ{mbZ?D?JpmG)Sib!Lvd74pfG$FGTB{r?H4c}ItL<-Y)^!q55XAN;SQ zL4TpD)y^!tIct?Y1)Ysno(p>!v|4n!Ra3(GB? z@9;W1?o+1|Np4DRy#$PsoB@Q`Bjyz?hV#lCHyzF|zU?}6unb)HDjJZzuL3ffKI?$@ zALNA1`8^@N+l*ZynrB@$dRXNy<(tCw1xVbS zhm2VR;gZf<_OPWr50lPMUF0iuu`=%U>aQ&Tj!Sk2U&nNh)&DqLE`#dt3Wo z`W>k_R{=IX)JXzHC))O3iF_q@iwTGO#C}z-37}43qLGfan^zKv%2A;BXrAl1QAdVo z9UuC{KIFaxa%wd&EsK>J#$+XdS9}ob(^r|(SBl!u5TUz24$V3@Jq54&s}~T6F`!vj z+LDm9s!v3^$j&~U`%hnzj7BY8$wUiZlImvStbfB7B3014H{8z$t{wrcL|LOY zuP)+G0Tm?-NCzCl=&zRxeAoI9o)Xgi>ip(+8`I4ENS(`RlV5HD&N`j$ery5ITV;mL z@srC${W!4p1406C;P8n{EOc_>hFj^X0`&{3J<4^hLCd^jOwXEZtc!CAJoE}rFB9uU zpUZZ_TwLrw`?u9&q7KcFiYMQOUx0M&4bLAjCd{R7mbunnihW<}U+`e=#sx7cg({|UH^+h0BFr!;x=>rhq%QRM{1O4<1&=rfN;-n@mN5XsO zfqaU~%YrAr^~hPoG0c0a%^5tmNniT{A1Y0i=@aX`=Xo7{RVTdQ=HY~yen!O+a(Ul* z17`mxZqx@y1S=zzR`xJ3aTv=rR`b?*>}S4D47eRz#PsW|b7HQ#@kNPW8h`8Gcb%Hv zsr6OaJC)gazT#6a|EXusp8uL#X>T3~0qI^$dKzX909@nc1Q_iXLgVHHV5+g-0J~YM zWIE&S^3rA>)PuKc=!x^)kX?Dpf5IKr1M-l?`tCu6P3*`6n+6N(;dI;qZ})4op(JX>V70$#07c_K(PJ9d5^%e|AG3` zuYTh3*B1KSxxe)8q@AoUec(gi`0Ddleq}W0!yEt_#9C> zU^;0T?~Px13+8x;WsIwF*b6qB&Os`8+6#I&AocdSU;+>P=EF_G=kY~S*UGLrVc3a- zmUSf;fjdP21dIa4&#vD&xBiRN_`x=gz(G zp|7zbp60afY0<93prbYLRgPaOxZ_lL6H+?)>aq6;ui`!7^PF zrglW(2yFFmQAwSNRn8K+)gLBB+`T3&A-A#BX#p~OG@-NLX< zlIx0DmnN${14y3QfN-bK?6k21q<$>auPn>^Pt}W5eDU!RWBrhY z7*TZn)uiy%HGKe&BN!eZKJnR4_)o&w{B8_reK&G{Ia|sZL7o+bJVxU^-pvIx)I!`c_2E;p%+ob{)Muc!*mHcK<7|>pS8a4{`Koky$Sy z$?m?DPO)arxJ~ZzaZesEz}~C>%CYO7{V?HK2L!h3xlPlt&gUu|^Zf65x*sm^#3{R4 zwa}&@(p%kSpuNhUSoEz(IU;ZIpSlV-dCK2)HjnLDA-nd*_1>yel-s#+@|3AGF+tDN zXB&>YdznUF*=W}lvzv5F*zxK6f&%RYg zM5$N0)`NI!O#~a22Qnk;h8MT#V+uVFbV9q##bwE-N7O zf)_sNZV{M_^3E5U&S%BuopvOD@Pg;-NS<4M*390O2p%wR#FPYLC6Tx6Y$I#XLSzI7M25I@;B}pG=fS~04@ibhEl$)2&+es+v}~%i zIO1CGVK-e58&6w9jvWe5dJ9N%+^8c%5>Ua!LB%&-9Qce6=cQlmD8b;nFbXmbxP)q+ zd15lU9N+>5Z)J9$dePnZhTnOB3GkS4x}moxp==`sFp7(!?9`v%SVWxPHwB4xN5RSd zbQ1G>XtQ;$!z~}Q;Lh`kKKX@Jnv5aPd1=IoS4`V0s!XfBMeTI}uli$8z;%Q0w18wq z)(!aPUxZ9yt1bXR1Sckq@VCwT!Z~gGdM+{$Pw5`^y$(>5XX>r~TNQa703OY-vW8b< z@vN4Z_xZved2a+?O_OQkZ9Z9rA+qq7eTBy9CwJ*szX30Z13Z97gVHlMWv&HB3HFr_ zU+ddJ*Pgsloe>{7|Myou{_xL64bUH~@9gqj|2+VdtA;#(^5oxAS9HwtN9<%ZKia0| zYRB~PLssBg7;ISn#%Xg@M;$ zZ5ktF%a8lubmi5;7jdK|F4F?au^2kE1IQn>1)0pcs5{57R^^V)!F&<3_IdJ`zu4A$ z**kp%D97}%uv>nSaw#9h1=SjtC__8DCd);?FrlOIcAWVYN7{mvA=RWatSvy3y)PM? zTCAVMZkX!OM|nk*W6V>>+JEIDpRzbErgfS3A{T#*OL$sKtrXAodi7TsRY&(fNNSrx zv-F<2EJ#tA$$0WKPsCC`wQEEjxMcB7wu-7P(41?nRdCYd-^KtWPu$SONa)}*`L#}I z)kpPj9VPO#yI+Y;g$8=>gDdN=bm4P+tP`yQU1YW?5UL@aU~)Y;Es>cq3J{q-acS9g zlRuo*`-D_Z)%d3Cthlp!WmB%?Q5`8h1+<2&-)SW>b;LU5DkeUuxx%tG;Dyo3nPrGi zrvaF3i7qbc_IRzch*~#17E*SMGiHXD9{%m{BVnBH(yXd}my+K~`!9UU)BiU9oq&I- ze3lm*v0d8uxHueY_`1$T-YAcF)`eKDn#+r=5XPPP6Dc2P=O+lfbsaEJ84g1l?+9oN z6PIyGWB&o`^pp4`s7myh=%TOS;VWm{kAAEFiLoH?&DRQ?*Tm@W#>-7G7>}~!Qu>^4 z1mhoI1vkuG6AyXCUiIFNC#p2W%KgyW2aScHUaZxp8)ZV70i9pp?k$~kpWB`5h1QKLOY3R4?cEh30q6@r*skV|Xk==&;G^HOZ${@n zgw?!fKgoBo+i})$qfMEp1i7GyVjS!+^Mq~ z;kuMK`y$P&3UOAw-KV3@$~rhR#^3k<_}{(qvB!UT{O|tkUH@Z%mlnMA!QcM)+AF^* zn)?%JF#Vm_;AA~F4F7J=KV`SPkUD>Cc%FxXFAtgxrepPd1ed4dPz@3t zwxF`kGorogAGl_=MOI9eHE7gfPjpK%^2ziN>&>BbAbfoFYkEHU%^nZtQI9>TEa zlzL)O>60ws6&lub@Ws6R(9Dh-=0tk_hN-hxomyHRp5e2@!PrZSvN``rptUx2sRwRG zx!C7Pzw^~MUqlR^IAU#Qb*x?k8cB5ti+wJ3=VS%1v6q!)50$o5Uyoin z81sT>;@gsb?C4UR;sC{Lt3Uj#*EkVg^Vb*jE_Qn=hli&XUh;}FFLXJ+alIZ~#;Sm& zkg3xeEfl?dE;^6-+=g2ui2k+TO;$Q-I_NntbF?p`>#iVv6 zwDGp1vl~Tb>!&Z^Zq!dGkuYmSm-@W+h`OkQ^{Ib*F2zT(8~b1UrF*SccEjC-9^{G7 z!keqOH9x9%+_`U{2tRonZvb^%&tK(%2VCljB=i%0;WGDCKvLW>_hWgjlg!t8#f6@% zCk*IeTZle+2VaPci}>!#an5pEl3zJ{J32r7Dn5SRy;>Isz=nz0>-2F5zQca3SKUfJ zd`Ox2!2Wyjm;QVV&wFJoh3^$L*758A?q0!vclN*ljO$wE*8g8#z`@-0-_V#lz)7I=73++ z9trQf7@Obm(|!ICirHWB5mN}= zcUxI>?=)lT*(ehbeKj_yC(d~g4hOoiT=DXB{oSYo=X357m-AD&aR2%E`~JW1JAT9C zYc1_PGNA+S5ji8{%Rlq8y`N?41XD>j>>oMMb~) zQKk(@rLX+(gD)m)6CHpzQ9t}^7`ma6FE9A4>y(?AAQb0zDK7074}~Rs`r|qerZ;>3 z=nH*EOV?8k!`$Pk?$ootkX@&Omez}`^T7OLsej|2M5*&FhBFy72uCpJ`^F$y~xa&V6TpIv?;DMMYOn|E^X+ zjdY)7t82r?B6)$|sb^wt=nmSh!#T2kbIUaTPL#;$%V8%WW^-lx7hb2keU7)h(hvst z97rE!F1No?t*#|1|HnWBi{Pv$*N=~{K6&Zk7ryd`9{*3%zo&+y^!JpuhhP3JFaN%1 z;_n<)mg}A2pzwf#)27|Ljt$d(<^~^K00zh1JOGau)pAanKQ$rD`r$uEU}=v9>wF)? zf)~j%=O6hsL+^#xMCTWR!VL@g$UJ2ZMlm|z!j5&#Ki1+ee9r0DBm$D-W{$$&2^X~a>-rB8QsH7*++T$b5( z3fCCJOI)LMB)7t={n2-Tews{4u-V|MU}&|2`SsYvX(GHvujk`dJ_O(C_&x zf9L71jW&OQ%zY5%cTp{9Z|Jrs$BysoujV~S@G%<|b zP^USwt*1@CeBOef^P8yqAZ}A?Xnh#{z=8+5t}{}ocrg1su(*D$ zb%Ci>-HFeY@tWrgJI3+{!xjvq{2AFd%TN5_N(}hH6$&iRU4oT10_59%6CKVNTYrEG zm(H-sYeb_LhG z>o*_5#=gdggnVK5w1&klb_)QWum6M;pYB=`1rFVE$Ole&8*6(EVa95F5ajO*tTgE_ z9^O}qimUZae3~B~|MEZjxeveR|JLF?dbzassJf8#%RlwXFMIy%`FBS5TPxeg13GPI z*3c}Bjh%zE<2WeG{#V@57FdZs+&Wiz-QxqF`c;kz@A1M%9QZ!H?U=(~rkxRJ)p#kkai^{fka{Og!L0B_WnwYe)v%u5C@zMZhn^AgZ6L~Mai z0{8DM;DUFY!(d@wk;(RpTb`U)CRsmp<_DrJw!i(R)tT zF6hg?<+Fc0HvL~6Ysp4D2akh%*^oXE!;rHfu%isUk;HN0IH|-riv0b6bsA375fFZP zWKF~YJJV55)Aq!AJD?p&4DDh)rjA#F_{oFY_1t}6pgHr`8ol(92aKq5Bp>_7`i;Kf zP`0cw>eo2ofpzC^xA3+Jhf9aze(0=kb zFX_p{c(I2;w&~xF*jKPF z8)=9c&&+7|<@^OCmBlT`38`7Aw#O{h5k)A-(_J4|!3P6U$1Q zZdx;H+Tgw47drEedVwG z!gM{MyJ9ACX5!f6S*Pdm;lGH#?)Nuq{$9S`Gk+7{>ow_fKJwvjjF-b-(+h%^gz(xZ zHfxL5zW8vYz1O+D`JCsoTT6p|nD>BOO@N_g%?GCrpA*E8zp(FoJ;{hpXPQ1tg6Rsw zewg=qt0usL*N?5%BnpgQPFmK3HF4$BdQlY1>}3d0=n^i5`lQkGuxLn@wIEQ0O|yFR#R}P)igff zr=N;7nKHVdG>y5=pSaJ0kGz8Da=Ok}*0`JVT2DBFds0GN;}u_w)RU_T?z5fIx>YMI zU_DR4ki`~X35p zxXag$1ZVYAKT# zaVL&^HJ%A4b#aQS=#-G8q7q+Hmf5bs!$0Fhn`$vk4Q_yZ@yX{iNWGk#Nn6%Z+5re| zL{1(a{@PFa$ip{!{+=FG$qRA)@^60m*FJlA`0rC}Y?8Jv55}rq2dDtHQeIhgDAxmD zEZXP78ReCsXdLF}({jvs6JRGd?uez9511i_(PjPFB1>o-b(ceH4 zjv*uRfgpAnTZ1c7onuoUYNh?DDc-%$-LTHTBoU{>S}z^k=_V-bxW+iPtIk4^o_y?F z=Y`Z8IymC>#Vam5fWsrZY@Ap6lOeLZu8EUJbQz^tuHi$M;!Z@xEpUf|OTXRJ(e>lB zp>^)*DYN8+FZVfPQRW2H zX^r3JH~OW>vtC{lYhO2U=Gfysb ziwlF>0AKuLKfmtj#~=Sxf!^EqeFxv$S|7gbn_vDju@7H;%4DPFfh$CxD{bnHi`P{j z40e#f8!?+Hc<)f3uv}jrAcBtrv<2T>Q~>&0#KANDAd$#MMOt-pz4UQXn($0uK(iiw zJC^+b!rO7;y_ui9L|n(=2;V}JcAR(XD!$QK`Bc9`=@2TQE6-?|Tp-MoEJE{QnHbH; zE8&%IiAzJQ%aMVN7mQT$4Kpiq-s*zbfneTOHv;zw8A~p2=VG z@Bz2gjjR>vMRVfFKl>5r`kBEgOY0>tc{-8B;n!~oUg8H9xU|PDuZqiV$#m(DVNu{E zpQxM<-JrAAu^>y^JwYb+UOP$0#ROUD0(jsiKan*8Cr{RwoZ#eH$fEx0wc{Nqepxz7 zIIW$4{OV)S7>a*)pi`W>$b%h;9Gnx!;Y80c6d#ID%inP2{?SAW%Ouf6u?G-t!}9Od44gYpCjQ5PG`7Z~j8SmE;kr!S1M z`}}PA@BM&2}B?9SA9Dk_IaU{A0GOC54RmpYs;Yp znD5lh+Qi3l>ZbsYCk|bs)5-%VY-OL_zgo}-v)6q>VW>=JpE`lu&Y4r!uje$GcluRO z664N=s7`|&&9%!4@1i?EcfxmEa+)X-R?NO$-!qlFaC+{zZsj`r1V&NJiPu=%F)`p4 zCUH0*;)N!sF6s!Jpt!rAZLnVif*zmU>Fmto7>p>4CuA} z9oI>)>;T;KA20S!NO+9t%Y>lg&-_0={EIJt{PBNSVDI_qsDIB(9f4o+%}@Vm9NOQq z9>DZcjdzX%#e+8+I$Sx!LHy~)zZ`f$PJY7fz*{bUJy(5b3D(#ToRE6B9MORVK4W>n zILHI9!kS0nNp1T>d@yO#<&{MPbg^ zxWP&mIIsIv@p=9_CoJ98B3%69*Yfr1Pq<@*zJ(v9)?r?OD-?pNh;vR{K2HiY4D_(o ztoySxM%cBEHFomsOe>~5)-{41fSq_EZATCVl=)Ie>4+|eKN%uUBYkJ1p+m;4eXh7p zfv}r;@7BMT5%at64TJ@Ih8%G$4-viWdK`bWr*Sp$`_iNuZsD;f%-AM!!zQnvJaFEC zc^HtXz04v zCNF*=>f(`h zAq^et7uOPe1+n&t850-LXR-WFu;OqZA(;JuqVn`>kpPIP9FeH);ypgtP9XcEAUY zeAp)s2wn~2$yp>wxd-p^Bm&EE`qIiwSOmPFvQJ5DcMCJF3kv@tV2f9%W$5!&U-l3SvC7!L%*;mz6B(eVMFU#_vP?h z@L`Z`d4F|8+Tm*}lcRnuAxcgymdnewD&c~=>~s30>&U~wcfRIZQfYeD|3)~=sQ_z0 zl)oAjfAC$Gr!Ek-9}K4+UKsO~R-7_#*kxm+iF4xeNt)xPd08ye=05Aqwg<F6p;i z9GE$mxNp?&-(A0Qcl|E5-?Ls1cIiu`SnF5Dtyh*Xu{Iny`G<8dn%&|{`wolMQs+vD zy@@7M>O!0woBexyeERr-hkq{quK)kzlI8_4P~i(8^(yg8zU7tQ{`}dqKX4Y&`xGI} z70rR?g_ZjqfXjmn;pHHdhLy7{uYYfvJFt^a>C=V-J(mM|5H3%=LaCGb(9!%y_$(`7 z#wAe;7)aRR<${%TK}{y+6)|Iay4lfpXe^q~ScH3q0qLeQe&N9;LsX=SXA$@LlR;!|w2- zf5xSL1cVbB;WQT=N-{PUz-ydu=nFsR8;%?m_2lt)y!x@nKbSl(;O&L@i-7L+^^3pZ zrH?*&eEcqLT7F`;^3d9#AusJ>eDs}a{;EXhM2A3TO|ci+Wa-G$B8)zLInXq17D%oh z$5XRQ0A@W}a>gZ&n$=15X-!`29;+6|DKtR&vENdPFcw|sS+8=$r}6MhRpt-RBA{|C z{Ul%K*CQ=9*P>W`$Xn?ybt$X6h^t!T&!z;h_dr3(!rgqCO*!Z4eQ}}WqhI8ONd+m7F1AOZGCeDEG9`dp*gH=o z@4lKuK8MCwKN2K+IGhf)!X}C06lqNcqpvv2pZT}?7kdj5Ptv7GbQO<#9{}+yL?7^~ zU30=$v9hoAuN%>+B?mBL*_KyzJ{dv@M*% zv^`fHHFlZCyiSu|w}d#)23X=!@mfE;mpTcmeyOf3m^_g{KSK9+{fD3P@X;3W0#52Q zynw=y{8gWP{ z<}4#`TxB`&`Je{~UUAk{j~XlNWz~w8dZ?9PAO7a=2AFPRU2T)0c*@s2t;cqUDvF-j zltb5X2XHG!fyA|J%38^V>$P=9;Mm$36Y8Rm?w1pFjQiFC95<}+6gPd*i%l20%PV~_ z?{V$Njltt-ZeG#I30=%<>HM9qh_*Nd?S?>~napz+M`HLZ{;jCL>Zp2(eeRo_1&I3X z{5vdt0|;ViA4B<%4*Ub||2%J_xn{v1iMl_ByX!jbT1z19j`_O8t+B3i-^!|(x)!1| z+{Tk|x^m!nAZ1QXWPpDe8fFK4Be;QySo@ZqZbE%wg|5wuUg6QXH=tFuc`W;^a+)ZH$y2y~;o5=von?u$ zAjRFPr@E@>y{}jN(*GdpyrHA!6+b%4{zm7I`trOf*xaz;pYyfrbjb7_0q{U{)VIJq z-FeSGgULe33n` zjdu}39Jq6Azw0>rK^-bGeG6cjT0@{|?B)DNEl(bP{nL*<*56Ef3VDInUE&L*`KHt_ z`S{asjo+pIwdq`TQ&TpQ15yVv91HFiX}g&m-D*Bloq0~qoklM=EFeixcKGr3=tTXX z*wGK(9bWL)FHqzyqEV$;=(LcG3lnwrKf=_Sry5r~zdcbv^7(9-yoo9umM0AFur9+8`sbW>;5Nx{bJUQ*z3+f`ZEGG7``CC6a2UitZF6A`yH_6p z@@IU9-KifwHpd$|dUlt6zPL>HQf>5uIm$O8>y z@Ed;c<)>d5zMsdo>qVD`g$;Bd=L2&c2ciOGhxS|38nrkdcoUicUR!%u^Ds{) z7A?RB4q7E%u72TM5*3aE-L#I!4i({zv!k=Oqj=9R82ro3@&Xmbz4*!RdK^UT#)DCW za>S>0QSB#i1rfv@{) z2Q2D9MZ`URD!m|CM<)=&k>4P{!65%l2y?pFDq=icE#B zNZoCBKS8yf>K%rz!41-Syhzd-7+D^jU#*u@+nA%U46q9g+h$9vdFW&IA7%bYp&`Pd%lm>Tw%S+8cen zozT^lGYcBV^Z_{PAE|>co4@cQyn%)5e!FkD=~sW@a9;52KmX-q?W;J>bjXIE5!|^S z;K@VY!COBD<&4jXKl8BWD=)l?Bd0KH{k0~tB05jx&%9B9q$;5BkeP3#58G+(HIvqbB8aV@eQNV*_gb06DZU&Z z{!aX^`Ck}++uvUz^hF=5(igpoMgK4R#H(K&zaRTg$5ZBAlk@e<>~mwDJ|7P2^^zx9 z-@xB-chi?+eL%#^y3*+-i^8&S?-y4js&l&Yft&i_*#%{E5o8GY^H(roVSVK*OZ$27 zWDdU3z2_Sq#~aT!(KqN=uW>2Y0m{F~54|gLpI2PU3&-BCOTB*Zr;eTLjPDnPVZ`-5 zo#Eh8aA2&QU(aZ*Q)0wx%<~tMT$Le1 zpwGp6b6x3Ad^t7UHp($+_q>K(|M>-4`=)E^*lF2U_KS6K2NvP#i>|AHo8~hPngrjt zwO?r>$DK4cavk+Yy^1CO{yuno9{=C}*TjGN|FbtFys#$k%nPgkrtmNR=9mA|hi4D} z!Rh2+P&DhtVF1vMn8;^)AGp=O%?r3bIO%SF5|rUCUq3h7{G_4KvtF$mqbZAUXi8a~-xKVCN!YPADxEOOR^`M)NrM!(0CKvlCx0dAxURRr z^I{`&*y|^T8tLbnW05fY4g>Ec{&_Jv$%0Gjg@2iLIjc?7z3xfbmbO|!*aJg4+ISik znw^NgWni!`{jZp~J6J=%Fv&g%)3TixV=~+vglSB^6|*|+Uvta7$V)WoU$6c(HTVn` zUj&xERZW*X=W+s=<;eb*vWRnntxp!P>exuUKtbZ(Yz(As%q(4(8@O_kTej306XNh` zteEj=cI&xP$$K9KlpysZhwYZOa?gGqIF^@q$4QAU`b`4xtw&Y(Pl3P*wnp>BA|(H3 z@x}jl?fw^k)h&DROPLD3>G|^~-}TL}{7-QLzFbx|mttA>3FHki6glI-9Omnicn5Uc znefD!sb2^;0!M3rFMLR`BjOvMuCimD2h=FQ=z`AU`Tz;K#is#5dtk?jH*-`ps5EIo zy?65yQ8Z+`QjQ18iL6;EC>;IB=Re%^Us*EVdb$o#tR=)emxpe0!+-A!Ke%E^0X`i;&=3e}) zO91=Y@^Hs^OAol||5y|XUlj5`|E`ZbeC0QN)8n&+@_jM&*1a!k*@}qY5Af4od;0Xx z$Cm!=bz7Myn8oD)7gfGjz-;XM0tn5V_5Pjq9#w}@w#$RE0mV^_^8jyvKBzYzWI_9h zLyzOJ_k)RY_^F8XJ~o=k(MR5oq#+u(%c>_noF@+atx>;8E+WbmgJzd}iy{3HQxSF7 zBJFQbztOj36kiL!-LG5mX~WTdI}A57cGW#0>IyI7evusj;y70qocfZWK|+B=YvT6v z7qMLzQTteND-Ko%?(kd*A#WlLCu)Tku6WRQ`e%I)hmLvz>C?p3tod)8Hz7`ax%Mr8 zv!~NE4~=u8#v{k1C$Hi2936V_GjeR%x5;0Ksh3P60E>#_{nQ&y0*~bBvK-tTjl<$R z8t!08k?u7t=Dm#iD>s&k>Xos#-oL`A{`mR-eE35Tzu@owzQ?~s&iB(eJNkaA%C&sy zC!YTN*PcK8uW=;)A(?XHd-ucO>N%jx^O6kbI*stKh><43GX{f9bUt7U1;8A6pz;8Q zCD(N#`*d$*+~k+4d2xvt-fBb`jyPTf{RTPwUFlh9_YqZeL|Ny;JNfOy(LA>2S`RUR z0}u5@Cyr{@)w4s(4by7E+!_){FnZl$Dp+z^(RPB@cQ-3E9BX4$$&v~SQ=-;tjDm%DR#dK z*Y#fNGCD|B9{SsHqsRd(ujWMCzKiI3FXwa89}%_edKa%UNuRFPXZAt_yAlcnho_gUAurrj5N%d9-;x#T->7W(+)@v|>IdHBVD z?*;vP{=2N#namEn4(LU8eet(E{o43PgT7TY@Ic+G=l%gYBYdEIobMgnikdHA;CLWd zn>@Q`kaH#D>!b+M!{A3l>-L&v_{;X$EiH>R93{D(;a)dDwrR(=h&~S3dFh zZH;>$PO3xi!@|~*e(5Kk{?XXo-?APm`FT-rK8TqEpkp!Dz6v{r?jnqWn=!KHD%9f^qFzF=-d&eIL3wbQo%c+f%Pcwl%SkMynIti4XjBDJH_ zQ_Dd#`3?9{#@(tv(?_1PN@4DQtQ`2J3xO=t0-sJb{H{lgukaeiw3ynzLp#J9TPK!ADen-F^bH=Q37hD)*lbjq~Kl=i{vhVv|c-sJy(S&1m2QaiB zg96D?BKIf(5kv|l}X-yyzVdT(f zuz^b=ki}noHCIl(z+)Ak92K|n#av&6(ze(gAuVMm9e@*-z1t;1_e zuAbO-b5LpF0G}mvl5(U5V@h=_j)`=q_Hg9|;Q;Y?ECS`$r5q{ZsH^J_e`3Vfxx`Ve zpZ;g3swnvq(I8d{FQ@V0k(N@`urj7JIE-fd1XdN#%v@3inUCuxp~97)t_Lha75P{9PF)Z zy1eh1KlLq{mV}w33UZucS4~S?xTcOuUe(v{W+?*Ggj@Sg{S*lsqsvNc_A74LPbFG) zb>fN?cj7%J*7!8BFYbdX(hvRYD^u8>Mn%q5P~Ddx#UzBpRi{ju-sY;E9uSj(T~;#Z zt?ZfIdQdX^-yOe= z^Jn|4*Mqaxt#0^_g{xO(P2)Oa-#@nt{0=G;1_ekZ{{(GxEfcz z3WYIgLO#qVuKeH|$GM6)A`59=+vywGIt{cj?(yZgg_GwEu}T!66UXy5p5yuJgxC7z z$}jw)2B-Qn&oxu(JaDudvoPniF?q4s6c7g4mi9MI+P%8OS-`13&B;l`Qa>hfUg|BJ z)Fce-MHsje2Fx;Z*y6)-Vzd^^hBNKGezv{S*QD!bL&P1w=`a4j{}=tpAA0=jv3%cO z-IDixrBUFQee(Iwd*zi^{R0PuvaHyphi zJ5N4u@r}vQ5dcXCrs4F0ngcJ(#PHhY#fYczB!(!)?#*Ir$`Bw8&0`EPvftCV(t&TH zo`m9C1n3NB4XfDQ)uNp)(bEug??b4Ct_~GcO&#@R=yH zS7Wx&n|T5^ecAOYxVZ8jEBifM_?)eEfyZ8K!-E}qua^g)BXHGN0y@vqFZoMzOpbCc zdKDMod-b=h4m6>Lj8nF`I&Ucm#|S7c2cg%YO%GLu#d*Crsy3eAc{nN$b#$0@ri>eU z(MO*38@H+Det#sl>Y|Vu(E-1`OFiz3ht>6{tQ*F_)UL*J6L{E z{CWSs*eT!V6Sw+(Ugc8WFa5+TUm6EQe@DOv+kAQ8%d>tVNXv1+F253J!hOPFgAXqU z6MG-r%Zs2Gco6k~%hGW?Zj;DwgxX$sTdxEp)&WOdJUEIj*lk?%*-bsfD@|VZFYmoF zxBbu=Ub(tH>OFL>{SYB^n%8ykE`3cbZNRqTmJ=(}~;gg2xYXrY{1DX7AIbexVBJuwuEt|76~I8;^UX^}O-`sIlvEqbhr; ztp9*smd5SjNhwpGC;QiZl}T$cfs0Ajoz`^h^>qKkX9c2JuKRd_Duz0gze2UGnmYa1 z%bn}=C%wOcg$&FRZ<8&xO8A;E%=Du&PgL7|-dN{;1`(;TcjO!3g_8u1F>)qefZ@ju zZhijI0A?M*cOp5Hm#A#yD^H$0eC209`uLq|?E8J5mA~JMJnQ?VAAkBa@%OQR`@P~h z7H3?p<#b>lEP&@pKG((#|7``A2Z@CJs8!tEFSrMehe&ctGYanHU*m7on>?xo8tOml zgFRt4crIlf@dvFR+OTfKE2O`HTb=(OADsXD=;ha z`R1I0nmFq|M1W6o+%ENAc&C2l7=C9Ajw1z9dR+Y--`<%B=Qbwkx^8>JOBee_Ai37( z_Q~VJzw+6SJ^oi6`r~9$9r|%n>{{k8`S{Df=lQdT-<`Iz3v)so;)CRqsTGilH^Fgo zH%tKel|?^b2HZ>UY8vF`5dHNue|IUlAU--_8j(Vgz+dRSKwF~+MxlPY{d6A;8 z==T4FdB!9m#%@ea;M#EJ`(tmmaYLFecz)QNAMWIq8WA2Wi@#{obuio8D0)95LlGwj4uTgMS#8Kehy zj_tqGFV(M$yp2DIrhYk`TyY(Mt(Z<;VlMazV+WiWhxho*BX@|}bycXKYLl)Gt7YL8 z)bur>emG6=(N^VrGAL9A1|tV;=ToM6`QptoNz&1a7TIxf=Jv-$tG_x{nkre%HK`|kP4 zuLQ(cZLoqXjfqBti~@B?I%%{;38~d;nyyq!fMz8%E^R_$T{a#QV3=QGqmpHiP-9oq zYPBW?u}f3=BQ(ZUx?EVTF;+%HkN^XW%nZz&v-jKU*XO#f`+lDHoHNV}b7s!-!o1IY zU)T5hy?#9RbKmdY=bXL6qIemmA3?cdGgD0RaS0yJCGj;cg-+dTsy^)dgGmp;6w~_D z*fWoK72orwKbdc8gzh8+4!wlO0C;sJDvXQ8x5C5F1d1z0bqkJiK{Ic(9GWix;6f$@ zMUNoiV8dqJq*&aaw8wfWz6fZLDKYw!VWxG)Z#AUv#3NtkT+x~Pfq%Y&N00PKRP(pA zGyOQ2Af{kDupo$Us6Vml@OI>TB*1g8P&Fk#8mIXMR3SM|d+1slV{E|bEj410^Tc^4 zDt%{dGKgNm`fKl~z9B}l~5CK=(Z#-lIHpRj!*8qY?uflr*wf;z} z-Dh&KYbNaJhmcjb-~WjGng2Jo=vUS7+N-MCso2kc&ULT;o!>tHxx4-07IVc)W8v|@ z$MVSsz7{@$j$p%N0mDzc!Vr^TE^Hx;KOt?@t>-#312A4i5QI7w@d=(FALKto3Og$B z+2F~yg0x~Jp3&tkWb$)P@*-R2iGvF>G^m?A=p*@soLoFZvk&p(z7P-sfn#1%Co?Cm z>YEK6`2iSx%p+|FZJ*2V)fSDYF8f>gu2!1a;z zmp_=Qr`n@c5m*8p374MR$q&4#nxOObo!nvQbyQbI5BDC0$T$%o6oEX%7io~(UmHgpNVTS%$TJUFJ+EJ=&@5mev6mrbli9Ov{ zucPV;M(eA`qh6v<>n{U_UItzcOrc~9Q1OX#3Et#J4)YL0jjbM?7XHevzw)f42b&fX zFSTnm=5HXgudH*uWwkG`uQCA#>+i&2 z`^$O4OVIQXZGDlNf9=NWc3*z)8}}bg+EqB9Q&(Z>Rq`MIzQglQA3XmHvOYdbtt?Pm z$Sj_Mw~@DRz&9@oI@X=7Zk5vq&L7BF@T_19s5TEe9E?Upe7tQHpM1dapobmveC_eY z*Y(^*6Dn>`2YhY3QP&*j$ei%-(W7taZ+wqWy^$a3$uumD(T4!tM!Y$`%}t0qf`;?; zUET0&BL#PP{inXT{kAq#fh>>L;s}ke81TxCv~@T*My+5Zzx13p&CS>ZlP;>3Ko|t# zH4&}sNElpkYLGXZryeN38fG-b%n9_rPQ=hvlnF1%t~v6T&)euPl}J=CB4pjSIAK?_ z1@I``0A{7*BgYC#=!(gC0M~eG%Y234^U#AA#C(p_4$!V1(Anzr{OPCdQ^pCQpo3GF zzQFVRSPZo@7*?iHhBxX3mh(W(^CU-M89yCfW`>{aQr8EC`V#pY|L<+Ct8!Q?_Npwu zihk*x58WiQe{*+eDXksQ=`|T*d9Fm#7QyK z+(5p$ae&jSK)be@LM}HXwe^?b3Bk1iD8HF3hSe{4@=3o5`po302O*ss#(@cEK*Awd z8-w3B;w|eBJ#?b)Q@CZCl9y7r?>)Rp$(#GDrW9!d%4;ScMgrtr8?ULa+?QkPGwP2( zYwOPy=L|}ZIt&-!$_rlM)sl6oSvW!Sb=BsE%{Lvy3%S6ysR2^Itg&HxJbvQGh z6LMSR;|_b5H|;A>O*O;mSPk;hYsjRH0T=`3TNY)OjzK@6sq7Z+HyfGF_xpS0&%OWT z19$D;UA(Jz#J#wBJJ2fsV{bZt^WpUHzsn+fnwx#OvFK=4F1#@0gVI*Aa%!V-g?V0~ zQ7(&)?7@uSu4hJ~_yZ@7e4YbakDKfAfLER#hX;hbEN1ALROrFaN0&HjX^RiHM~PT+ z0iJ#aIFb-~N25E;#@%2X1SC^@v)$r{E*T0|;dA|!sEd_k#32Zcw^*W;K=0VxZ)GP$ z$3f8eX7A39#Xg0%Jk>`Yp$A+%_98FpBrdo)&*Fi=qF2ooyC)QBr4{|2mogS{Br&r` z{-)|c3rOBJX>Vzdz^NM!(^HtQUpIQ}JdBd#>M}lZ&DmA@ZWkDqluoAZ~IZ zJ?8R*e(sll?)M*k;*P!ihS=?;9f%ff&7cE+?5^{FQWnzNW%1vDt*&FcV)=^OR-bgU zR-7$RHa1q^qTMJsj|F@zUfFBp(xXm!eS~*m4@ad9a;&rS6ro;_=97upt9+-Fu+QUt z=F&GdoB=#c#=Np$8Q=Y>vxpylG`TN}`vjokS$$$2at|0Xd3ymVJ#s^_U*YvMp(-xu zof2c}SQB3!(3LeGG&G8<`zZ7>Awpsw!ulioSbIfv|bVlg3*8Yk0EqYrD@) zUwsuL@>h!q`kVy8(WiWF2$YFoI8p~eLp~E2!=(suFNK4Ucnmyf(!ixJ>KDiOfoK1q zr1SDme$W1&q|7#;lUpZx2VVL;7hZ98IQwz=%cl0z0vF3{UUl)H@Brz$?~wY0?^b;E z6@goFKJ5(X_8f@?(=I*~=rBXHt`N2ozB^0%^tL%xY=1|3HEN41k(7`NcA)ZZ&$|o&frN!&vi6rCv&IJU*}bJwo=|(XhOa5j$L~7mcki z)v4Q=a7NNLuB@=2oL47O z-!h}{r$7cWh0E=0;#z*KyuACFmJBSUhFfipBUATC|4I8I5*gC-nd^->iDIyhvjcG| z%wkI-W{x~PZ_#j>s!`_xG!CKEL?Kh1X-}a>ilN6J?X!M)*Xvs1CtT#s2ZGcSqQ_sW zUr^LTfXA?Y4dGcY`>Xl7f2vCz@*+K->H9h^>rsf1;N^YFdhw7E@f#oUPS15;M1%6HG0R9Ke~$3*D|~?_q#LsmA8NP6L;=^)KS}e??BzzZr#S#0r^hA zD`k$*L=JI$MiT5`+={_)F;7wpj|ipW0<3} z#4|Wje?Iqto8Xm~MpEZd9UPt#b*2Dr0ys?eh4Cw9-1Mh)CgP9yOepk;7srBdjvNpa zawM-vFE8AdG_--Y#f7N*7{2PGo$I{0FB*)C$-h28gBY*i z)0*oQ1@|Pb-5;+bn936aEby0lF2QGAnFw*c@{85q^B^v|YxRRS%@X#2Q+;Y2aOxMs zlIBF>k_QLo(fgQ6{yensme0}srvey`$Dnc}L-KN1hFhPCb<7~ch({IGi*g#o2Cwp! zpIC6RdzJic|F@ZYds}pXPA?pr!8>sC9S?o8{Kew$vl%Oq4Jw+{7Mxq?>Wq(7n|M}o z>IuOAAIfpTAN=Y05X$I4*4XMIpODM=vqStSIX7m+5B_|i%!NG+wE?=`jGs5?F$YOs z;s-Mod#q#i(3gtutimG~4T`|JwQT8%9lQ>5ta?sMWA_=5fPz(D-A|uoeDV1U0!lt- zHse*#een)3YCM4&kBVkSMW-Rv3eIhZi1?xug(`EzDwpC8IsrK-hW$11exM# zPR*s$d=V!*Gu4~G81(v8bFn_e)-j8Q(`O-jPW}W$Sb@j=-0%MKgLm$~e~!P+s{<^( zvTUP82VQ!|`M-X)J9{G!Kt52c(p-=%N0%5kD&M#iLDSJ&1Qdti1n41Vq${xTSDa9q z^6FC^PwB3OA8iqyEH1_eGYZH|9TXme+BgEO!Y1G<3oQ(hK=P09awCXsq9tGf=}Sa+ zx5OY!+I7(E6%Hi#1BQadM!ms>muBeD;yRlbc}}>x|IP%zSf`ng3$T7FQS5S6DNWQQ z3+V{2fc{q;_bSQhfx|pq$#Y6;-25A7ftMhpsW3}524;^&54`3e|GEA_%O>mfYoabk zKNL*$s`@bMHz6Ze9j4}QS%XehR`5#ESCpA^u&lRqI9v$AF#fFI0QkV?>WP^BQ$2lU zPNS~P^o>Lf?0AM;VGi>!;!_#MdaXXoEF32%`)`+T``?Dnc3tnld`s3*n|1f)cRu*H zWT}0pwjvjP_9fa#H(8zG&nZt9xOgH;&mH+Zf#=DA7lNsqd8`johNlC)%nzlAFLtxY zn_kI>C%E#R;w?6o(O-FtcAZ(AGOO|YZ?{iCa~$qF$t`v2{+VwA zFeOgvMO~_^7^YbTL=21Pg^ak4U&#}v;;!8r5tn{id>vXI)o11wA@a!kB1ZSuRdL;K zbA6Lni?Gj&EP~;ID+uM~ z2Z067!eb_{5I@_nFY!#UWDI?Q!~5I2PTT@7?j%mh4*%%;OvT@G}^Xa~Mr{y0FE z+Z(+b^FqYx_S`US!B(s12S`~gd}H#&WN99`Z1@Rdl!$7nmywQ5cY?o zGip(@s9Qp=U->k@xqMy^_?STNo8_BA=!AY&gIyHmTk=}Rz)OSkc(?eLZxBLe2xmf7 zmcb)kbhsuDL*OdA=1^Z~r&WQoP1eTHCj-0U#rotjh><}?vH^UZD6-bEx$`Y?^fB_B z)tN)g`UpP(rYW@QOYl-B5hbX;I-pQ=fAtM~3fLg)l9@6eR{g3VB`XYa=-?Uml*Cql9OgRc3gzFd1=l)I{;#znij@;#30g6F&fu9Wx zIJ@YN+U3{!Zr}FrH|R3PwDvNf8-xz%Ukp6k@BcRcI-oWPmS?mz9;9rtZj|xzXA(SC z_w)Fni+4twU5ypaOzg*t9h2}OWS7RzIN@*UdZ@4`E(U{a)AJfZOPV3b#xcni5C_83 z##TT^4y121ggA-H_--kDBEsPw^2IyXqxM#=Z+y+*@v{i4-%1N1%0!>*A`Uk~9P6B@ zKZt$fCmp-0jttP4`;&bO#B%+?Bwl13C6aec^B}TMUKA%+Qwb>)n>%x)?97V*0ftMS z)*UrY`J{H<{|at!!J9MzGY*xwLUrHmz@n`t;^FZ}9CUl$l|rVM1M!*85MB;*0(Ko6 zkMSy>&=HL5jkrlJRQm_ZApuh{9ci#${Y|a`o7a2g>j2t7T+>jU>4o2PJ#j;nUJ)Xn zgJ^$?{F(pu7yha>mo=L2@MV!UkbWoN!Yk#61^tjb1t)B9H1qhvb`J+jE_50?38W4{ zo}j?<1t|nuj~x#>qj>lUe9YK;PO64 z-e}^e(881n`xdgf{^(x_6c1!*;fV0rkAe*&{GH}w7qI)k-^mNAQL_er9z?5gj@w_wv)zEcf zTI~jyof{KGMJr^nt}+ghO-+@}kg^drQNS>86}!6D>Nk7fW_rd!C-a(-TDOe>J8&4)pe2d4>GAWzI02SeuRk*KHN1?6Nt@WklxJYlWh=HyTRT^3f$ zCxPZOn7nB^j3MdV(v*SuWKJEu{)^$$hX97Deu)$w2UZ-nn^oTEEB(s*uQ2gvzg&iB z$*VZ-B2EuKQBy+)Gd|}7$|r+Po9K}IE$Q9c+<}+e zasDghA^S;brvDZ}S*^ZyS-}@?bALcpyB<*I>2?sy#X9%ZVfGsV;=C$&4Q}tsg zXMrbP#TofJQ*F(9j4{>$f39Ek^<~wEkp5-TFsCkj@-dR~qL5<;Y~mQib*=s}e+Lq; z;zXSRUgN;*A>q&UQ)v2=6#a`!`NI&nwC8h_0>k~VJmoE6B%b=kv(bKk|24ba*W7>S z{^usoHhq{K81LA_ByaHQz)NmFf3xfeZLVXZ&SQq8D_^u?#80ZDO^39wewIo#fr9wI{0I8aTHw49L`qq1#!kRlfaB8L^rOq^(62-z1%+7+9(ll-iHt%o zE{T(YB3RdHZ{bl`6x|H)E{%2J`F`oTa4rfXE<@#wiu)E0);)R9XGN(Z>(1IN2BL5u za$mzS^$A_VYgnK*?h}o--+xekL+e*RaM%9b>fc_EyaO!BN3OIfSO@<29f#*VbU6QZ zS-XEY_MdT83#!(&kMcp4CqgaEc`*8eQrtl(c$Pxyb8`odL+pK_D?pE5R|PKlqcS>d z1Q{X<$PGaNt`&+1Pq^eS8t8nD4%M*qZO{?an5IKZTtuSZ15W`EJJ`n>caBf}Dr0$( z+(LKME1t)rPl_TAV`nb&@^~50U~JrM(9C;X18@eCz}n26_AYOA-~{Osb`~Ckbf640Q_ujdG@9f{^ zpLz$z74fO-Y|Peym%jP%tPA&F_zC%Eg14x-HsS#B#PYy~nF|lBZcO?Dj^AwZ#skJp zbe_!85R90w>2yuTJfN93MAZ=|e(;s&=wX&RFhhg#k!Qoof)!v`lpTnsq8eslt z2p_KoeJu&Sq&bT|rk{ev4Mk0hIsykKW!2ueRvw_>1jJ@T-xL=@i+m!1TsHz8Wu1uM z#3KS@~`a9f+g|}1ib27RvKy72U0ay^(vM3!(lPabw)JzF5juYbdEFT`Yn7&!lI7Ius0x) z&Kv7z!Oiv0A1IZjd~n>iY;?3O>x!uTLat_$iRD8dce{7qaP97E?|tL`qn)#jA9)8@ z(T`kdQy4n%^*?&J{m?A;h&L0A)9T3`#__=CjTw8tTBH@e z+Ar1*qY#dCyReLxvJf1|h6)aE$;}p@XJ6@at^)9(pTc6Npq^s{TI-WiYrSYO@*nat z4r&AnH~xStsM8#*@9kh#EMm%Mtgxf?dFS$j(jZ_&dt0juZx1u~6HLEShw&P@4LjV% zs;ghMXIqB)vL_KH*)_DW1m<{mAcZN`zY%U4jcd2FO{0`P00iKd-aDE(Rh|XWuOc-4Rxv8jCoN+ zy&_KwFXLPnff({uod{QX1u)l*2lIFJkzaHMhvIEqb?LOwuIusDnnZJCpOfKueGgeT zOoFI@W=;eS%JeS^bu58{Ceh~r`pS$-D@TrW*r2M zI^^;n2Yc@PU zW#-(@PyVJC&n%Cw!dV1qn=tV_#%3XSHX33{0!l%L5&1JOct&y)0iuxfGQdAYS?W~= z>Pvb6nXmQVd;tL08c3+sYxaNgqBC!p3q1Xt9U`C_^jl{NIetKT{rc{)3r}ih7ZLZn zmGzaj$u9vN2%rL(-8E$xFb7KxiHGk7%$kIbQ$8K8z;p_?2sGbM6Ey9vKvtR;_OK28 zuV}#NKl7|JWG1x?^eN**0bSb4d~Wn=Jp!(~jDibyylPr~iTC<5_wZY6dsBn!aQ}2> zI_+w_1`nc7U3g(uANXDN9Ym9r@jFUwiTZG=bhbQ z>M*6+h{B;4;Z=MH9*jC_Lyja`oUoWaaYD562`_pvP58pDfDqQpykRB3V2*F;!*i@V zs(uv0PB6?uj__d_af|yF_(h+h?_5-L)Ft3#Zy+7EvW7YreN$kI5mV#)Uu0{-7CQb& zU=o^9o~2;HUB>-asP;p(GXHhqMNbIhaqE4#PNQ$=W}xCQ0>a#{PRP2#xsH`sIHLZU z*D5t^uivQfTN1Nr#A(I8+8hTu@>U&8I##pHyGhOcHTq2ZV<)@a*WGvL{{QH>ZT#4D zfF=6asBfx62VQ*V;R_FE56M3h+<)HS$VX(n9rFf*cYJ6@C7rP`w0+S)@Z!1T`K%|D z03nG^Ol^@R5K2SMSPUws(Fe4dXqQr%fdbz$UqXXd|Xzno=DZ<9q4(l)t+@kW~$-` za0CXh=rd{_x23hnxEqiIuSK9_gOG!hcnqFkal%fW+2ItO^TRiQ-(CA(HKFb8G4H^*;ve&HTYy_`KYaEl_7{Fq9?}=*gET!T^G&gb zq_<9p_DOu=bx0q>Kc<@-tLf%GA`;HX4JCF!4!As!*gy$H@M%NJuSnJ3pZp0&Tx5u! zd>R+L3cpCeBo_P>j=?4RxCloW8Y**4HozY8#gBf14xZIzV+VLxS<|+N|7-y z9fHqK9!L7c{qMTQ7Y&n?_heBmp|-A7ggymsu9tbOe+OdE^&16K)}nr;NxZp^2lUAvoV(O?`YF!3T(Z zm+{Hefr|6Ch`r^*x>1zHrcgd95GSsx+H(XR@&CEB{cG;OWB-AGZjOFr~2!J|H4{7`a`nj$5s!JJXk`~eaj!jK(LVk4D)e)Uk+>x#93YgH$2XY zVmT3E)?4?_`n3^@N2Q{UEJJ0)?%R?^Mc0*x?lZxK!TK{h0kx|^^lg+)9kYucsYnNN zQ*wc|e!4sXsuCkh!f5M!-snlJQ0RDQ;?>6PcHWQi(r*nLHPzR1GOQS^4uRSg48V|} z|He^F_;Y#Uh=!AYnr)zBqwt8UeCPUXZVAo_`5e`Zm;Dbs(i3o+cDj!n?-*8rqp$tZ zMk>w&|4vmlGTqdJVwK~EuN9HV;a39MTcKTf= z?<4+sohBXtaRHGqZqKH9J6h{LDTW3=jQWidyvwRzu}A8e)69AlFFe-|vVj>BdH+fI z^ZvgiKhythv(`5M^mKqb^681TMOkz}e|+%aZ1>~x@O&OledhX$2W#4o78?u?YHkc& zM8>5Xw>^acx}C=p0=!x*fjh#tM<0?(YvML%OPJzh;^g61|MA{K}!J1!3t!sZ`K63+CuY_Bo~DyP@g>5PrRgmhlPDs#xUJ@j|VG2;K2Y znl!WWJeFU}OQlj^74pKLo!!u$QOP8 z;n`>RU-$>|Sbb%Gc-RlTFZxwlJWlzfEj!j9IBu@l^bJGMkV|_f8zu;G$@qi?KWr#C z^+ERyW4Y71VCn^5aY(94{|emfQ^JML1T8ok@H0*p>N$e*S-gu8J899l(mBEpV)3Us zhd>nvbCwqd`ll+YNqjb9v#R4r|CjdYQ|PB&^20#~)NcA3+=n3aO1{9LDMepIvpG8M zvUm8H;4v=+w~((13m7~HGwT7}OW*%ehzMDe&7&{mgYG;B*8QqH)DNj$J03F``5XnG z4fU%@z#hkO)Nd|vJly(?-xHuP4?p%s!&?E;eF<;0;37fx%tJ==`q`6fcYpTdx9;!3 zwp|~e4#;<4w%6m`fnWUQ{XKu`uU-2xd6aJ5oyf1d&?iU#lPAZXF}sRcZ1zmfPgE3u zSvN%epU$y4#D!I}Z$98drd>io!1}N+a6>{BNjDz-&tjBWbR)iGWt)djE1vT7f1#@w z|4$&MQv{s`y7-|_e06yE;KfBZI{hCnHRnqv5#I9G8py-s1*lB@Z{Vpw7%Ki42Vvvu zTfUU2brahM)}!cwCPTfRdt{)b>6P&E;@*$2~?S2D{tLHPt z5Fd1f4e@vKtI}kTd+pP9FWV0PXyW61@m2CTC$WXE4!r2L3tuDO+WTR7NPkZ}!}jnM zqK)G2v6*l)^PyvaL#b-Zxex51Q6HN|2-=2V6oeGiU+a7lhPBkm1YAtwSz1$k%SRmU zUB*QvzZIH%u$2K8u6S&2F|vHpC;YIBb)MFxbNYA5`=wYCu_vc*jf?e&uU{XITPNEIcANk-VJoA1Xd`u$$)C&U3q4RCL zz|&|KOkU=tcE=FXH7`=X0Hd49bxyrkzH8c!lQsCeCnvja`uOeppDgA!db~Tpig~>A z*y6Viyy&jOA3QyO{(qC__6yZq4|0Iw=^YLt`pr1>;Te3f~E}2*SV(N(e(purI2homnAH@e^_A}4;bT;cr=@?W33aR@j z6EQrR^;-%gI6qGoYtHQ={ZeS-NZ!ACa^3Dfk+1rHeW|ip9?uT2!XD2Yw%98jxa9{9 zPrvWJ^YTvxcdwk?_OObvZk~^FLznowMa&9xfZ28*^AO)*DeF@sXePv0vufyhVHtXwK89nUm>?K;!m$O;bXiM2!2%Q1*?dX+AF6bY4d$b(Y8`O1Gk-GDV#|J2Mtj_|WJA*wnN<4Lr)#hJfb&Pu$GwD9#JW4SVVza`dqZiMj$nI^elFPhxl&sUKt*03Nvl zpIOXPSh`X+5sL}7VV$T^!u!P!*t{{^D9uLz@N49GQwIlh1NNbbXbpJ)QVZzge&$OZ&$sGDEb1V=xZ>4f zbX>e8F#UlIgkRJtuehunAd^21l&m8(H9oC2h8bL0wTFYzCGCCSs3i)?gU=2fb!3J* zk(Xo;zXQVO-X|Z|duQo*5wD;=QW*gnPv4LY+r`$OaRxm(FeBj1Q`i!(Ru2fz`eDF8 zPyJDb38mdE$cWGHRIR`8$7RuvsCQu>X-E6GR+DP2)vuCE{7U@>JYN5xk7(B6yo#@Y zdM)Zqo@0df^Ed2w-}sT+_wOs#Ho6i!5V!71Ol`}lci`ONaPp6DyYN?K|9+k90RCGA zr>%eoGxjy1Pa8uDuHW|BKodA@lxo$j0e0ev6Z!A~KykK}NMgpT#8fI@j!~?QL@n}8 z#PNaEoC&StGS4INVX2no83xa$)eA85BVX!FKn$XeyfOGm*yqF{&#E8Kh(`rkOGlu+ zf67#rUQ>6aev4pl#jlEqNns`kP z&qC02+-iN(;S7#^*|~9(|KxTteQypp?re#Pp>(E=-N8-A4R)}LU}`QB5B<2H-vXIX z+KCg_)Q!2yblc_gqMl$UZ!F)Ubo~h1E>1{H2<6<6f)TsgXh*I;!)q?iNP9*wR?SA? z#j?ch>rd1)w6clMI*vLcT?1L9*`ASofPR^S5C+ygIQ25NLBf3iUg;J;@=H##XM6~u zCxqh2n8K!YZvEZw|HZYt-G6@X9sB<~(%vplfDUl0p8%v-v%{A~w*h!Cwt>$aagt4aundtZ-wf!q5N;1g@--{}{{$_;xs@tW`MDroop^XNPBit}OG{|C$&DFj%s(h{Dd8c0OtAIm&Es5L zulkI>M?|mUhy93Sd0X}$mVev-D*3nl|7h0O=1+_cj4R@ak@J>i>%dKKI(*LI!3%Ge zP5x`p@Ur)gFgF5byzJysC~j6@Iy8)=*Ko1cEr?*QrQe7#GVg=rH7?S z3IVmrTlG(lV|W!(9~(LS%ma1ONq=TQJs#m$-plyGyJY<^iQ@@jB|V$hn^uG?GKEog z1(Dv(lY0DGxI^NkQWC>f++JP6|dg1HjCvASe zY!07IN4U8>>}(XwefJdfVqcHOh zd|!f>$fFyUBBt<;Z4Tm~rdzANu=n`pNI@zwYkNDw2f@Z0I>aGv!TgSCd>w(Sd;*z$ zR*crWjBiRV$8E@MUpeZctco8al?#koT-`Z3C%lgB6?h%Ht{9AOv#_eym8i?6PEcpn zD-Jb-o9i>IzQwE7y9Heomia~@=#mdQ;OL9u^n*>!1F6aB%geMfbP9ha04E;tRo8uE zUyjvdtFOc~WW0hOYQ(`yJo3tUX6{Jx_j>mq5bHPJcgOz6(b=v~+z$8(dE(~3W!^e) z%bO0*y!WBgJLExrmFzn5yv`dyfY~hA!J3A-c;eH}GVy~>bqCy}!$wjYbPCyk=b&qv#e(!z(_@A9U0eTH!XJn+W0_`e7TbxkkSbbBoro%>|P(KO5+S0Mtdj2J40pAfDcT$8g7qz;#eEW$=oyu~|c>S$Y;g=F)e1Hr6R1Qz%JK@Qox;Wyp&!M6V)AEi7 zhqTKb7WM0E0!&lK$X6FKc*@)5%FEWtJn%syI z%w+I8_BcHe*$3Bo% zzR`oYC@nM4K^1CA9OGs9N_7~eKjP#(P*%Uij_7_FG<1SlWpteN4Ic3kfc#}X;M1?F z6d(E)WWp;Pr7}l#?f8&~y-D^Jf#{D}3v0a`d9bm~lNy^#EpaZwO?QrA0AGmN% z=6^*VX89L7vVp_{&x6gJjUo5Q+98x?n?dXdHfO_wZyS(s+CFT!`Hc;%HmDgf&U1f~ z;I<)Uf{r781|I1)Q;pa^qYyDi0a<49cpThQ@e|;KC^X}zd*rLxmBOBaKBphq|J3op zQT>z?bqzq{gKsg-E{1+>Q-vB%2P?1C5Fa=V>vEC5)MIm*&i18b99ZUv0)*xFXFh<D5K}g8K;3_sQ@%Qd)P{UeRF=AluYEN* z36NhGQ4)4=kx!UQPYf-5))DP9C4EyF#nG0|!LQeR1(5LAvt0DVU|O?a&)2X3T$p~a zesUgx`UefoA^S!mVpK)?jJjqcKX>fi*ImDR^~c_@|0Uqt^~u+PSfWq9!nTU417H86 zhim@jZ(R5`*#N#<9_^>j8wDFk?tHPu)y6$76Lz%NA(_TDraO%Xj~xY_+-TT%`UWSA z)KPlvMpa0Rj=A7x_!$_wvw3YxH_Qx-e0x0(DWK+%2fyZPuJA`1Za}#_-dukkOcbzKf0|h3n*5BTeofsY)xj5b z(-o^oc&?5FXENfbJmL8@-y;Rm)aimFwp{1x4S-&3U6?8CkLCc5CeuaDW#^Wc;X%J!m&!>n`qc*!rX>x}c7 z#YjND_jz6DvESx?IT1NPz*j#eV4G^3xgW)!}FZ^eb0P_qVeakwOMM7NFlm(pp&(~kK`)eP0{r+EB zfbH!`-vQR_-JH7DV%X5E|TI--LjE*?qMr+M-<4DuEoH%~cog2-B z%N;9`K2TWr+J1#8H(pqaeSXqqS{o%6-2_o-*A&F*d1t@EoL=yxouVVJ;uFgi63&r9 zn+Oo_oC+bwdbb2$b5BC&M`Q@TUb}jYD2H?PHsr9%E;5LG7Y9;gJ>)JD z$JSrshWeLy^2@$-gQgflsi!8HfX}`GNJCOpCHqjffBIl!sLp9ZjUO<(Xh`dm3%RDVy{g zWD$HedjWpCP8+QIbjg5@<-;lp^V-I5+}L>7hf`wD z(AW4Dn)vu3h~4xeT*irc))kIP#>mc(exv}pVz(I1Og%9+DB0N6^k~$amylND<$d+I zEwMqH39;!W_Le}HqAo9D;r6Q39En3s&I;!2OTy)^(+YZmT@ASfV$Y%0whqJRAbQiGwCiIYKXh(?pQE<-tFZ$tiL0^p zt>)H&FT3^d`41iBhY0NsU&}_czA@{PiG#~Vy07>$g2#rIJ7aEy1YB-tc=S4Zb6=D& zIqrm5#rR@6=-7{>Rg3@M*qRocE|>8QpcE{DY8q-;?~{cxLiQ(gh^ahNE<@z!@l4lZ z`J5d*`^=7>1#@5A04uWgi|K_$VJjd^uA({0|J0aqg3l%IFH9VAHD2UHoz1PoVzmGl z;T7J6^57GFr>*o=<0O#*@mz=Z#DzQO0Q4#n_NN_kjq;nm11n0@AC;ya;Q{g-1upB7 zxp5SqSdU@vi**|DB2cYQLGSlJAwR$WwfDYp|C>!=8(yUyUU4=mpNK%g=Uw}xyTkPi4i8$A7UXZzjXklpk1*_dj3X$PVjW5dmjFuDkjgJ<5bX*Rmd+3wOV zgB$}QhFrlj^6hpNV8+a2PB#@U9695nzKxOaB&Zuy8latWR%@^_Z04T4S_qaX%Hu9AoJ{x{|QZ@%nH zcmLz|&-(gZ*v8s{an)=+**efVaLdmhuD$1IKX!)AYKgd!}j|){9O7C-5DQoAMF9fSj5^!eOeQxVd z0?d6xH~UwHAj)OnRUF~`ws>Fn!l&%s_Re$r3q{yQTL-EGwPMP)jkXR99gyz`T>oqT z^89OLqxufny#DRnV&@IXHY26_cBvbejeJ^~vFef@3^mVCC4tkiy#ff9Ma(=!<~TA} zOnwEqDy*1P@^~@DT6H-x^*YZ2RRTUG(~w2br}@5S_Eb$J+pmpri|ZCoM&<}RjtH+8 zGhxrjKA6pmHU%Esu>)MsLHj^63tZxWRC%;5RPf6dg(ymmsb}cMc3koBFRvy8b0SRB zBxhMuItf@AcpRP!lo4=3t-r`W10hIVGhdne_sjZx!{P_a+V8(Z=_A&o*~e+yebc!4RT z7V*3>I?7}wE%kD|TyT2CUyHmz%@h`?% z!>eR+B77e7;aKv>Gx|n-m%@u*wOB9tfohq6rd4^_Z230R>Yhjx0yUcVncT&p!+%cu@ccUtPdl8y@R#LB3A|P|x6i1Jjje26R^x#{BSGgp4AXg68-BwBJcix3!MiJMuevWjDuJ=X4UC)YH$ZL7h)q%yt*wBd&`q=+|bbw zXcVA)r_J%fidO-Olk2knF|27RoH~_keDucr5zKr#Pbl;`*)3nQWkQjMS0k?VIOr_m zP5oD#$F7RtnlIwy2bge@Z>F_Ye%J=R2-EL}$LXjVSDdIbTv=Bnz?^=dkoF1Z_ig_X zY2O_;e&+7`{>^Lm_ruw)TL&(u1HK|J2f1Ok4on?*@!vlDo(Jx`@U8M~$8VKQ>RBu% zHoVx^ZMWAwQ~j}bPD;fo4e&9cTgq z1zj4V(2bd>8Y9X5{-ZMc-s?YO_ofg3_5H_-yN$LETz&^)HC;YoLv9_IJD}eYI6Hs# zs@>T^J`5b5hkxD(S!}tt$$%{_ZIJu55ig2EFYv=As(Qmly0-CpPw`qZS#14d9Pn8_0V4sX>bG$>4DmxDg@_+Q(}gn99DSpnj8^~~;qQIc zl)!UPgCmah*?@vvD#6e*wN6Uy1Iz+;D3nY+he@|JZro(@;-1Kv=CN%_pbJUQx&8K=JSRedoZfJkhv zKNE;f?RO`ikZ)N1@O69n^Zi@*zdmYjv#kSi{c=liK z4~M@b8~gB22y;V?)ySO1$^N;Nb;NQ*btF7RF&;HWejP-h!+(U$#!dW@?@?7LKX{D6 zYbFI7ZayI9c^=_K)e-UQLSH|*i)`CkriuHVv&KWb6sisyYS3v=RU0%o9| z>YMl@A^Ddlg!OP5Cl*ZMT{k~z(nmFiP9W^ESZ{=jH1T(ijnP#=)77E9a)6;=_8q8% zIe))D`Jfc_=BM7c`+@hL+kd!N+i2^+W7C20NqlT#Y^qxavIAcvKUC=O>!<&*?47SU zJM6wfHtE$h==-U=mR||_&bru`V?!p`@?c;`CZtCJ2QRPaK??`dnU@DB0-4}g$Ks$8 zd_v*swWrza#MeV7#|jsGpW|Q3jF#2d7TA8ybr-5fu3gyS3EV*Cxx0s;>h3e z#cHB49C`7tB_`OM9$~Ui0hn^$h`zvCz>C*)eIbMA)!>qI?_K&h2s-+|B{R)((LWF!RBWJ_n-b zu#B_Ni$L%qtKmb0W61E0s~MpUT@iWR1V&D_^*K z`}Vi_>DzXFygI-m@p#4G;%*%nI`Ad0JN*8K4rhN}4ud~0o8@!WxjYyKitpGL#l8!J;|~Xz@8E`w{XKacpyWC51f_F7D&pNQanhuW0`0KjxQMLt`~kU)Ux!>v zGkGBkJK=k@!4t&Hupb>K?qfUn#uA(JhK ztplwC=MIOHAA7@vuRJ~5f1~WLuaMpQ8Mdd&8wYOg=)sFUx2cR9GY0`1wgS=gu`A36 zcE>mI3LhIj2N!%Et~~fEfiA;YA$k?x^BG`^2?tf2KURz?5El(_%ka^k$RKe-^h^ke zBG%wRh=|lbW*}OD**YAGz+`0Xkqqg_016NK5SlU-kMq4IZ2c{0_FCqHC`%b@F z_SbKa1^cIDLw}k=+J0+eJ$T(79=Yg94<56#!`n>XSpL41Gb=j>f$N2;3gQT*V8*4w zWC9sc2k9qZ3XgJ{e0RaC@ajdRhTuYNaY;Yah{KfnDz@~eCLS_4Dy}?rTc6Dy;J{p} z|8e>U|$NeYq^$KO_Hu;H%|iddhNpW?B2e z#Q~)KvyD7=?l`y>2TF8Wz>0?tEe~K|;aGg-AO87LUy+69AfiL=j!_!YcdisjPnS2=7?_ah%oZX-xHvT%e*}6j_4;1X&lfoC{P5~wS!FQp10@=yyu-VErt&x?~0fR zJH+ObEWAteTtD&SEB{CUo_0XT%5obs4^a7frLL~NQI8K6&Z2(DnGK@IdmNDC)qFjL z03YL2exVa_uv=aG{l}!vpA*DCI^3}PhaWk&|J^a_HrqPz#OnZ$)DtiBE#s{NM>=rJ z&mXRR|GRcC*`1wzRs6HU7szSqC#iDsK=6ScU}lybUoCv)YDRg>4-oTLzBvzMKQYWy zx;o{9gt;V8q~YgYo14GArL4#qC$JX2^USG%6p4(qY?QO7i;7QPd@dSn&tA-#wm(ZT6eq1+zqGyNDh@iCBm zKO%xZEB{{q9isU&AAH09-+44Zi+$$epCCuB*T=!VtUsh9e&r=9DkOBiK|>s8jD0I!=*cDM zW=Ma~avt#c1CRXijsCX1cgy|%nUllGJO2F_?tXFm;XKvbZS>^tKs+i>{zA73w+^gz z;HEboe(!zfcmLkm;p}EP-fosd;ze?h`9CwX(@0qyeBW7%n6h53#i>Znq zef0yZ%kX)^{A-TL*MyrNz4;)l1dh}v0GA1W)K&GP;C{C^E%2tIZHW&Q(59=#vR4fF zpfvL;zQ-aWb*e@yUuJv#XL`T5-yhz!+n>Da8BgE+v)}yo{k;}zd)qp26?TAU<|-_G zD|zd{vIF|}2Y%;WyBD0D`Ue6zH1vak{hoq6aM}rM2TXotn@5)mPj(KlI1l}FQe-@Z z{opdQ*j>>9#81A0+6g!F(N#=?DJyg@#gD{{A)E|=9pN#*fJ)&BWt`3yn z63_4fVh)U=l%g-`xBR^Q-MeJ;u50D`1=sCaKp7ZIvnU6{KO`negM)}$7y{o^H3-ZgL`$a8-AJXYZt}HJjv^Q@~!;$oa_$o*`1vH^6qr^ zp67ht?q9t7FYM2E-EF*eVC%reJHQilan$DBIn_4b>aIlH`1>iD)oB)KV1KBMT3^^CnnZOjO zs%V&bCh`G5o$~4jc|>wYR^roH#<=pfKan4>bJ+bqqV&u1H}l^k@!xaZ(|5o8+yCwU zqan0iwhn9^cmy4Yo#GKFY}Bm-TL+GIKn}tEzx&<0-+y|td*1Hs^m+0(&z~#c=gFb= z+}+tu=DX*}xp|EpkesgZRIVM2!nIRap~8!o4>)kuX#Vh)EPwgVE$HVT8I-}8T`#1< z?lb=Eo;08@zw)mPlxZ_Jok|VwlS1ArpBC=k?M~#nyIX#1-g{5vzxRFD?q5p`$R2ci z-#V~$;8E)U&+elpxCw0?*gA0e9k}J3{H4QdcAxvnv)yxdhtucDvHo0PKUWUl&pA2l zpDn*a?la{J=4ZCJCFDe9 z@AnVLcN*>y^oM08*Te6K?%ncb{oRt*doP^r?*7Bq?*7&Gm-5DbZnLcepUw{Gv%bBy z4s0E`!aMNXbB7zRl@9~*orGtfUXTw3C#TQepYH9$f&6*6Ur!HDlf(As>*b6#o0cu}hve-+!9Jv8`S9_eXg(xA3-3XlpY6}= zDp0`)_OQQS`1i;`{$au0Bj29?u<-8@+lP18?C!Zv4*k2&?LVp7+iUB<)`2Ux1OGpr W^}>qgQ5#|a0000pc$(V_R;n=dZAVgVH%@AhBI@#BV5~owvaN?MWlBF_)?1pCjm6FI3 znL4E*WQii#%2ru2Wjm93XVlv{=X&4kdah?a&;8ur@9)0v>-WcRQt=KLF}OS&1OkcS zu$E3B5SWi(5KM^wbLy6d3kU>R!`r!7@sA)Lk4PlC0sy+Xd0&1$A8_~Yqf1NqV1MtP zb$K}&037ZX<0uqM0KnfVwWU%q0C4zrnLUk$0|4vW<%elB8vwvm+_0k4?fCKviZz|i zPqwL`V(E0-3M!7lzyLR_Zc%L*3@mWN`WDTW!N36&42@>ZVAuc@ERBW{02N24+tBG) z1_c99`G8|kumFwkhGPl45WgN9|&e}bSwzCS-A z*s1)Zpj3f`zyH_pZ=n4!#s!Qyv8{|*=d@Dl`{KS9vWMqCiwsC+}R(Zcs5 zzeoPn#xBVDe*E4$|0rl#ki3zzF&sh8&&WoCAhMAl7{U+Wk9R}0(V9RmfFFfzTx}F4 z$oU@pJ|BT(V^H5gFd2dNUrQkTpY_A}U-AE={iiUe<9T6MC%LD)ytjw)viIie{yPJ& zYu^q%7#U_yylgMj@>E-R?d(_YWSU}+M6G10~Lw-H=+vzi*Vc`*xQPDB6aq$Vn z^NC3pE+$_}NlisFuzqYQv z;Xz~5!)Df_$A3O~+VYIu+V;G?qw_^qcTexjzW&#PZ-(9ukBp9uzk5G1IW;}=;p3;- zx%q|9i<~cCmzGyn*Z$&uTkkkB4&}EF4zR^oezO(5HUk2Q!f}@7F0q5N#lQQwxJp0U zvNzSE?wD?#4lO4*gr<2hNDfc(^r+7XIDVqrMuFy^?k0b_-(#}iYC)O|Ql~9=XAnY@ zlIxiQ*{9NOHXGDG)eB2Y;RH?2E)VxE6Yg;S`Vbd6)fD*xtXJsPG>)O#7nmCFdNniT zG<_nyH@|RSObey@$mb@nL{|0HrpUp^Vmqdk+CLs~ z*)+fOi~Y5uuMGcCiaWW>XhJRF74t!ticM8qWyv9JQ;darIL+v!Ny4*RrCnhO?Vs4e z+>(Ja1{bx=(%m1AA|(rwzbvV=j4%5o?Y#CZD=|U5n%HRTS-*6>+)6t&NF||grY~4- zTbx`6CIez4c-|B}NFb4+M!kj^`Yp7L`;}?7bwNnUd5yxSelfArE zTaxC|RU^ZM^Z~Xa$1XlQK3sJ#Hq+DW&n`_v_I5)#`*yZ+y=4A`l9W+$Q?q%p=0o;0 z_l7UqVD59v!^!;f?HoHs_^M;LipZ_tV=n8AuWV?kT(!<8&kIGBH)^-8ip(B9qj9AV zMQB8rmhZ*Qb8$Irr0c7Xg#=5(2Ad7eeeUgO9FcB&Nj9bFIVo`IYfnLQZ!O!<%wSzN<#kGtGnvU4$=$hQIm)rEA z+0k$(mYQ_-s<|7hta7v1PC{K)(ruJ7zEgSe`M0uw`ch>4(73;Y&k2nq=N9}Xxa!SA zD6L#G#(T~oMH61ggc^cja*#|k)u;khi)ce~p2(;?6_!{~P16C5ESI9dRn&m+s~)Rf%%Ceh!oXH2`GUuJvu9A~~Gv+z0~GW6n57 z`5^t+y7=X2VZE$^=)q>8724P`%OVXjX~am|L)9R^_gI}qZ*RRT|6x}!JkMv3zmz@r zH*fX=FLxtJZo5Yf z8z4t-BNsG%!K*dT-f7Li!<6RC`h`RzV-q`IZIG-c2n{boDyuW`&bHR|tZg=pKxSJ<{kP+UCLdlARsg zxTUmL1`oPe4UHEa>5;)({#8qgsoR&$M~LnqM2nn!pIE?ylA49tBf_l&v8)kT<_J8L zrb7lDBI~Hg4wvirgB$IY@7(`DP2Z^^be9(N zU+GHgr!uAIA>zyKMRuO7 zz@uPeCz-HfcXUh}q(MnHH@X*z_tqBsI0N_ajyviv;|o69bbOAwn>@$1BQ!uh3~FAi zXTrn!lnRp$0Fa29(vm4}RyT)(bAdilF4o%7Ej`K%y;+w@BXZZoB|QzGc7UvetuvYz zcn@i-2@meF7LmbAF9anyIK9(^*LhxwPCS5MoOx|0)<3N~+BF}+RcjvFQ$?62%|YB0 zUpeZz#(>+6T@>TEDM!xf7`{;)af#Yt2)0!?o1=uWXXUkA$$1_ks*xT%sq9x`k#o*t12&9;I{gEG>zN6T2Ns_})1(1{nD zTRFA-cm1Y^Lu-E7;~;Yw{;uj|@^%>f7+t(WOcxcUy>%ZU#DxSIHPVM(Mi`+k+>+7f zJy11A5N}V6Pwe>!flDl?VZm1IQaU_~6RTyj4tEzrGh8%4w6>-kd3s zHxI_&`$+*7plT^vtIKC5IqhL$dujMGI0sgxfCcv*PbU$Q*SHc57kJ#~r{#sw!po6$ zMn#Z<6s^g4ky!a)ipZ;j#>+=R1#+y6F52IrOOb55lrh_^R$Itk<8}WK)-%@ zJ92B_Wd|BFfg+lBc;rqVcPRth8~kXLv-o=j%Pvc9H$_WHbZ76tBd7JJ#jJSA+Iy0` zzx4e@E2{D}%1NIx{gFv>c^+PR653C4*OF>J6Kw9Cucw%7kH{EQaeqe0i z&Q~07V&CTuqGQ8wjZa{z>p)eiFY%Pc4d+>J*I|z0jJ~}&tg}%yGF1)XecetjVH3>y zd7h|a$BQkMu7kxWUaP1O|MSAKNZELC?()>+Ew90*S(%55Fn+Z-ldQu)J;IpZFgO*^9sc diff --git a/packages/shared/src/UI/components/ChainIcon/index.tsx b/packages/shared/src/UI/components/ChainIcon/index.tsx index f60e97f9e413..32f60101aff4 100644 --- a/packages/shared/src/UI/components/ChainIcon/index.tsx +++ b/packages/shared/src/UI/components/ChainIcon/index.tsx @@ -21,7 +21,7 @@ export const ChainIcon = memo(({ chainId, size }) => { const chainDetail = getChainDetailed(chainId) return chainDetail?.network === 'mainnet' ? ( - + ) : (
      ) diff --git a/packages/shared/src/UI/components/ImageIcon/index.tsx b/packages/shared/src/UI/components/ImageIcon/index.tsx index 3836785e2bda..c8082f49b266 100644 --- a/packages/shared/src/UI/components/ImageIcon/index.tsx +++ b/packages/shared/src/UI/components/ImageIcon/index.tsx @@ -3,20 +3,17 @@ import { useStylesExtends } from '../..' const useStyles = makeStyles()((theme) => { return { - icon: { - borderRadius: '50%', - backgroundColor: theme.palette.background.paper, - }, + icon: {}, } }) export interface ImageIconProps extends withClasses<'icon'> { size?: number - icon: string + icon?: URL } export function ImageIcon(props: ImageIconProps) { const { size = 48, icon } = props const classes = useStylesExtends(useStyles(), props) - return + return } diff --git a/packages/shared/src/UI/components/NetworkIcon/index.tsx b/packages/shared/src/UI/components/NetworkIcon/index.tsx deleted file mode 100644 index 1b416f3d7928..000000000000 --- a/packages/shared/src/UI/components/NetworkIcon/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { makeStyles } from '@masknet/theme' -import { NetworkType } from '@masknet/web3-shared-evm' -import { useStylesExtends } from '../..' - -const useStyles = makeStyles()({ - icon: { - borderRadius: '50%', - backgroundColor: '#F7F9FA', - }, -}) - -export interface NetworkIconProps extends withClasses<'icon'> { - size?: number - networkType?: NetworkType -} - -const icons: Record = { - [NetworkType.Ethereum]: new URL('../../../../assets/ethereum.png', import.meta.url).toString(), - [NetworkType.Binance]: new URL('../../../../assets/binance.png', import.meta.url).toString(), - [NetworkType.Polygon]: new URL('../../../../assets/polygon.png', import.meta.url).toString(), - [NetworkType.Arbitrum]: new URL('../../../../assets/arbitrum.png', import.meta.url).toString(), - [NetworkType.xDai]: new URL('../../../../assets/xdai.png', import.meta.url).toString(), -} - -export function NetworkIcon(props: NetworkIconProps) { - const { size = 48, networkType } = props - const classes = useStylesExtends(useStyles(), props) - - if (!networkType) return null - - return icons[networkType] ? ( - - ) : null -} diff --git a/packages/shared/src/UI/components/ProviderIcon/index.tsx b/packages/shared/src/UI/components/ProviderIcon/index.tsx deleted file mode 100644 index 9cb90bd0194e..000000000000 --- a/packages/shared/src/UI/components/ProviderIcon/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { HelpCircle } from 'react-feather' -import { makeStyles } from '@masknet/theme' -import { InjectedProviderType, ProviderType } from '@masknet/web3-shared-evm' -import { useStylesExtends } from '../../UIHelper/custom-ui-helper' - -const useStyles = makeStyles()({ - icon: {}, -}) - -const icons: Record = { - [ProviderType.MaskWallet]: new URL('../../../../assets/maskwallet.png', import.meta.url).toString(), - [ProviderType.MetaMask]: new URL('../../../../assets/metamask.png', import.meta.url).toString(), - [ProviderType.WalletConnect]: new URL('../../../../assets/walletconnect.png', import.meta.url).toString(), - [ProviderType.Injected]: '', - [ProviderType.CustomNetwork]: '', -} - -const injectedIcons: Record = { - [InjectedProviderType.MetaMask]: new URL('../../../../assets/metamask.png', import.meta.url).toString(), - [InjectedProviderType.MathWallet]: new URL('../../../../assets/mathwallet.png', import.meta.url).toString(), - [InjectedProviderType.Coin98]: new URL('../../../../assets/coin98.png', import.meta.url).toString(), - [InjectedProviderType.WalletLink]: new URL('../../../../assets/coinbase.png', import.meta.url).toString(), - [InjectedProviderType.Unknown]: new URL('../../../../assets/metamask.png', import.meta.url).toString(), -} - -export interface ProviderIconProps extends withClasses<'icon'> { - size?: number - providerType?: ProviderType - injectedProviderType?: InjectedProviderType -} - -export function ProviderIcon(props: ProviderIconProps) { - const { size = 40, providerType, injectedProviderType } = props - const classes = useStylesExtends(useStyles(), props) - - if (!providerType) return null - - const iconURL = icons[providerType] || (injectedProviderType ? injectedIcons[injectedProviderType] : '') - - // a question mark icon as fallback - if (!iconURL) return - - return ( - - ) -} diff --git a/packages/shared/src/UI/components/WalletIcon/index.tsx b/packages/shared/src/UI/components/WalletIcon/index.tsx index 47a7ed91db1a..5e895274ffb0 100644 --- a/packages/shared/src/UI/components/WalletIcon/index.tsx +++ b/packages/shared/src/UI/components/WalletIcon/index.tsx @@ -15,12 +15,11 @@ const useStyles = makeStyles()((theme, props) => ({ width: props.size, }, mainIcon: { + display: 'block', width: '100%', height: '100%', borderRadius: '50%', }, - networkIcon: {}, - providerIcon: {}, badgeIcon: { position: 'absolute', right: -2, @@ -28,13 +27,15 @@ const useStyles = makeStyles()((theme, props) => ({ backgroundColor: '#ffffff', borderRadius: '50%', }, + networkIcon: {}, + providerIcon: {}, })) interface WalletIconProps extends withClasses<'networkIcon' | 'providerIcon'> { size?: number badgeSize?: number - networkIcon?: string - providerIcon?: string + networkIcon?: URL + providerIcon?: URL } export const WalletIcon = (props: WalletIconProps) => { @@ -51,7 +52,7 @@ export const WalletIcon = (props: WalletIconProps) => { {networkIcon ? ( size ? classes.badgeIcon : classes.mainIcon, classes.networkIcon), + icon: classNames(classes.mainIcon, classes.networkIcon), }} size={size} icon={networkIcon} @@ -60,7 +61,7 @@ export const WalletIcon = (props: WalletIconProps) => { {providerIcon ? ( size ? classes.mainIcon : classes.badgeIcon, classes.providerIcon), + icon: classNames(classes.badgeIcon, classes.providerIcon), }} size={badgeSize} icon={providerIcon} diff --git a/packages/web3-shared/evm/context/index.tsx b/packages/web3-shared/evm/context/index.tsx index f43e9fc5b55f..996a6bc6e191 100644 --- a/packages/web3-shared/evm/context/index.tsx +++ b/packages/web3-shared/evm/context/index.tsx @@ -24,7 +24,6 @@ export function useWeb3State() { const tokenPrices = useSubscription(_.tokenPrices) const networkType = useSubscription(_.networkType) const providerType = useSubscription(_.providerType) - const injectedProviderType = useSubscription(_.injectedProviderType) const walletPrimary = useSubscription(_.walletPrimary) const wallets = useSubscription(_.wallets) const chainId = useSubscription(_.chainId) @@ -41,7 +40,6 @@ export function useWeb3State() { blockNumber, networkType, providerType, - injectedProviderType, walletPrimary, wallets, chainId, diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index e2f6995cec59..afb2a4ed9180 100644 --- a/packages/web3-shared/evm/context/type.ts +++ b/packages/web3-shared/evm/context/type.ts @@ -8,7 +8,6 @@ import type { NonFungibleTokenDetailed, NetworkType, ProviderType, - InjectedProviderType, Asset, Wallet, PortfolioProvider, @@ -28,7 +27,6 @@ export interface Web3ProviderType { provider: Subscription networkType: Subscription providerType: Subscription - injectedProviderType: Subscription tokenPrices: Subscription wallets: Subscription walletPrimary: Subscription diff --git a/packages/web3-shared/evm/hooks/useInjectedProviderType.ts b/packages/web3-shared/evm/hooks/useInjectedProviderType.ts deleted file mode 100644 index 229265bdb308..000000000000 --- a/packages/web3-shared/evm/hooks/useInjectedProviderType.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { useWeb3StateContext } from '..' - -export function useInjectedProviderType() { - return useWeb3StateContext().injectedProviderType -} diff --git a/packages/web3-shared/evm/pipes/index.ts b/packages/web3-shared/evm/pipes/index.ts index 5e00b6e3a15d..d78c87ea08a0 100644 --- a/packages/web3-shared/evm/pipes/index.ts +++ b/packages/web3-shared/evm/pipes/index.ts @@ -7,7 +7,6 @@ import { NativeToken, NetworkType, ProviderType, - InjectedProviderType, CollectibleProvider, ERC721TokenDetailed, } from '../types' @@ -15,60 +14,46 @@ import { getChainDetailed, createLookupTableResolver } from '../utils' export const resolveProviderName = createLookupTableResolver( { - [ProviderType.Injected]: 'Injected Web3', [ProviderType.MaskWallet]: 'Mask', [ProviderType.MetaMask]: 'MetaMask', [ProviderType.WalletConnect]: 'WalletConnect', [ProviderType.CustomNetwork]: 'CustomNetwork', + [ProviderType.Coin98]: 'Coin98', + [ProviderType.WalletLink]: 'Coinbase', + [ProviderType.MathWallet]: 'MathWallet', }, 'Unknown Network', ) -export const resolveInjectedProviderName = createLookupTableResolver( +export const resolveProviderDownloadLink = createLookupTableResolver( { - [InjectedProviderType.MetaMask]: 'MetaMask (Injected)', - [InjectedProviderType.MathWallet]: 'MathWallet', - [InjectedProviderType.Coin98]: 'Coin98', - [InjectedProviderType.WalletLink]: 'Coinbase', - [InjectedProviderType.Unknown]: 'Injected Web3', - }, - 'Injected Web3', -) - -export const resolveInjectedProviderDownloadLink = createLookupTableResolver( - { - [InjectedProviderType.MetaMask]: 'https://metamask.io/download.html', - [InjectedProviderType.MathWallet]: 'https://mathwallet.org/en-us/#extension', - [InjectedProviderType.Coin98]: 'https://coin98insights.com/introduction-to-coin98-wallet-extension', - [InjectedProviderType.WalletLink]: 'https://wallet.coinbase.com/', - [InjectedProviderType.Unknown]: '', + [ProviderType.MaskWallet]: 'https://mask.io/download-links', + [ProviderType.MetaMask]: 'https://metamask.io/download.html', + [ProviderType.WalletConnect]: '', + [ProviderType.Coin98]: 'https://coin98insights.com/introduction-to-coin98-wallet-extension', + [ProviderType.WalletLink]: 'https://wallet.coinbase.com/', + [ProviderType.MathWallet]: 'https://mathwallet.org/en-us/#extension', + [ProviderType.CustomNetwork]: '', }, '', ) -export const resolveInjectedProviderIdentityKey = createLookupTableResolver< - InjectedProviderType, - 'isMetaMask' | 'isMathWallet' | 'isCoin98' | 'isWalletLink' | '' +export const resolveProviderIdentityKey = createLookupTableResolver< + ProviderType, + 'isMaskWallet' | 'isMetaMask' | 'isMathWallet' | 'isCoin98' | 'isWalletLink' | '' >( { - [InjectedProviderType.MetaMask]: 'isMetaMask', - [InjectedProviderType.MathWallet]: 'isMathWallet', - [InjectedProviderType.Coin98]: 'isCoin98', - [InjectedProviderType.WalletLink]: 'isWalletLink', - [InjectedProviderType.Unknown]: '', + [ProviderType.MaskWallet]: 'isMaskWallet', + [ProviderType.MetaMask]: 'isMetaMask', + [ProviderType.WalletConnect]: '', + [ProviderType.MathWallet]: 'isMathWallet', + [ProviderType.Coin98]: 'isCoin98', + [ProviderType.WalletLink]: 'isWalletLink', + [ProviderType.CustomNetwork]: '', }, '', ) -export const resolveCalculatedProviderName = ( - providerType: ProviderType, - injectedProviderType?: InjectedProviderType, -) => { - if (providerType === ProviderType.Injected && injectedProviderType) - return resolveInjectedProviderName(injectedProviderType) - return resolveProviderName(providerType) -} - export const resolveNetworkAddressPrefix = createLookupTableResolver( { [NetworkType.Ethereum]: 'ethereum', diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index 14fa0a440a45..686796893e7d 100644 --- a/packages/web3-shared/evm/types/index.ts +++ b/packages/web3-shared/evm/types/index.ts @@ -54,19 +54,13 @@ export enum ChainId { } export enum ProviderType { - Injected = 'Injected', MaskWallet = 'Maskbook', MetaMask = 'MetaMask', WalletConnect = 'WalletConnect', - CustomNetwork = 'CustomNetwork', -} - -export enum InjectedProviderType { - Unknown = 'Unknown', - MetaMask = 'MetaMask', Coin98 = 'Coin98', - WalletLink = 'WalletLink', MathWallet = 'MathWallet', + WalletLink = 'WalletLink', + CustomNetwork = 'CustomNetwork', } export enum LockStatus { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index caad03b13e5f..9d79b2a4a94c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,6 +120,7 @@ importers: '@masknet/backup-format': workspace:* '@masknet/icons': workspace:* '@masknet/plugin-example': workspace:* + '@masknet/plugin-flow': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/plugin-wallet': workspace:* '@masknet/public-api': workspace:* @@ -171,6 +172,7 @@ importers: '@masknet/backup-format': link:../backup-format '@masknet/icons': link:../icons '@masknet/plugin-example': link:../plugins/example + '@masknet/plugin-flow': link:../plugins/Flow '@masknet/plugin-infra': link:../plugin-infra '@masknet/plugin-wallet': link:../plugins/Wallet '@masknet/public-api': link:../public-api @@ -269,6 +271,7 @@ importers: '@masknet/icons': workspace:* '@masknet/injected-script': workspace:* '@masknet/plugin-example': workspace:* + '@masknet/plugin-flow': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/plugin-wallet': workspace:* '@masknet/public-api': workspace:* @@ -405,6 +408,7 @@ importers: '@masknet/icons': link:../icons '@masknet/injected-script': link:../injected-script '@masknet/plugin-example': link:../plugins/example + '@masknet/plugin-flow': link:../plugins/Flow '@masknet/plugin-infra': link:../plugin-infra '@masknet/plugin-wallet': link:../plugins/Wallet '@masknet/public-api': link:../public-api @@ -545,23 +549,49 @@ importers: '@dimensiondev/holoflows-kit': ^0.9.0-20210902104757-7c3d0d0 '@masknet/shared': workspace:* '@masknet/theme': workspace:* - '@masknet/web3-shared-evm': workspace:* '@servie/events': ^3.0.0 '@types/use-subscription': ^1.0.0 async-call-rpc: ^6.0.0 + lodash-es: ^4.17.21 ts-results: ^3.3.0 + unstated-next: ^1.1.0 use-subscription: ^1.5.1 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 '@masknet/shared': link:../shared '@masknet/theme': link:../theme - '@masknet/web3-shared-evm': link:../web3-shared/evm '@servie/events': 3.0.0 '@types/use-subscription': 1.0.0 async-call-rpc: 6.0.0 + lodash-es: 4.17.21 ts-results: 3.3.0 + unstated-next: 1.1.0 use-subscription: 1.5.1_c9c210d65bdac3c3f586a38a4275dd8c + packages/plugins/Flow: + specifiers: + '@masknet/icons': workspace:* + '@masknet/plugin-infra': workspace:* + '@masknet/shared': workspace:* + '@masknet/shared-base': workspace:* + '@masknet/theme': workspace:* + '@masknet/web3-shared-flow': workspace:* + '@onflow/fcl': ^0.0.77 + bignumber.js: ^9.0.1 + lodash-es: ^4.17.21 + react-use: ^17.3.1 + dependencies: + '@masknet/icons': link:../../icons + '@masknet/plugin-infra': link:../../plugin-infra + '@masknet/shared': link:../../shared + '@masknet/shared-base': link:../../shared-base + '@masknet/theme': link:../../theme + '@masknet/web3-shared-flow': link:../../web3-shared/flow + '@onflow/fcl': 0.0.77 + bignumber.js: 9.0.1 + lodash-es: 4.17.21 + react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + packages/plugins/Wallet: specifiers: '@masknet/plugin-infra': workspace:* @@ -795,6 +825,9 @@ importers: promievent: 0.1.5 web3-eth-contract: 1.5.2 + packages/web3-kit: + specifiers: {} + packages/web3-shared/evm: specifiers: '@dimensiondev/kit': ^0.0.0-20210913111737-84c17d7 @@ -836,6 +869,20 @@ importers: devDependencies: '@types/use-subscription': 1.0.0 + packages/web3-shared/flow: + specifiers: + '@masknet/web3-constants': workspace:* + '@masknet/web3-kit': workspace:* + '@onflow/fcl': ^0.0.77 + '@onflow/types': ^0.0.5 + react-use: ^17.3.1 + dependencies: + '@masknet/web3-constants': link:../../web3-constants + '@masknet/web3-kit': link:../../web3-kit + '@onflow/fcl': 0.0.77 + '@onflow/types': 0.0.5 + react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + packages/web3-shared/solana: specifiers: {} @@ -5580,6 +5627,31 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@improbable-eng/grpc-web-node-http-transport/0.14.1_@improbable-eng+grpc-web@0.14.1: + resolution: {integrity: sha512-ZsCTzI1iKUbmQjB5DNZSI5/hvdliuaPpS2h8mVj1QzynL3IFb5NrNnHVHbfcH1wbm26Ka6Z1CrKFGvKLrmbFIg==} + peerDependencies: + '@improbable-eng/grpc-web': '>=0.13.0' + dependencies: + '@improbable-eng/grpc-web': 0.14.1 + dev: false + + /@improbable-eng/grpc-web/0.12.0_google-protobuf@3.19.1: + resolution: {integrity: sha512-uJjgMPngreRTYPBuo6gswMj1gK39Wbqre/RgE0XnSDXJRg6ST7ZhuS53dFE6Vc2CX4jxgl+cO+0B3op8LA4Q0Q==} + peerDependencies: + google-protobuf: ^3.2.0 + dependencies: + browser-headers: 0.4.1 + google-protobuf: 3.19.1 + dev: false + + /@improbable-eng/grpc-web/0.14.1: + resolution: {integrity: sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw==} + peerDependencies: + google-protobuf: ^3.14.0 + dependencies: + browser-headers: 0.4.1 + dev: false + /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -6225,6 +6297,83 @@ packages: rimraf: 3.0.2 dev: true + /@onflow/fcl/0.0.77: + resolution: {integrity: sha512-hgFW51Va29KwlzhDy6Fm15UesfXluRTR5RJn+zrm5d5HFfkquaxKOnMGT5waKVFn5u4THQIE6v+OnaDDchGNpg==} + dependencies: + '@onflow/interaction': 0.0.11 + '@onflow/rlp': 0.0.3 + '@onflow/sdk': 0.0.54 + '@onflow/types': 0.0.4 + '@onflow/util-actor': 0.0.2 + '@onflow/util-address': 0.0.0 + '@onflow/util-invariant': 0.0.0 + '@onflow/util-template': 0.0.1 + '@onflow/util-uid': 0.0.1 + transitivePeerDependencies: + - google-protobuf + dev: false + + /@onflow/interaction/0.0.11: + resolution: {integrity: sha512-Xuq1Mmx6Wyba/F/L+QLQs0yJeQDsIDwy5SKk5vrCuVgIj0yD8k506g5L8ODrbM1LWll8i0tQsoOi0F85vNl5sA==} + dev: false + + /@onflow/protobuf/0.1.8: + resolution: {integrity: sha512-Taww31RrpJMr3fkWgF2HR2TcRbAoPbMjwRYt9IlYknyRX5YTzpaU35petdqDRfxwmfY9mRxHbiInujX4aV02Hw==} + dependencies: + '@improbable-eng/grpc-web': 0.12.0_google-protobuf@3.19.1 + google-protobuf: 3.19.1 + dev: false + + /@onflow/rlp/0.0.3: + resolution: {integrity: sha512-oAf0VEiMjX8eC6Vd66j1BdGYTHOM6UBaS/sLSScnc7bKX5gICqe2gtEsCeJVE9rUzRk3GD3JqXRnPAW6YFWd/Q==} + dev: false + + /@onflow/sdk/0.0.54: + resolution: {integrity: sha512-4kC1kpxUvWUvWs7kymWX6bJjmch155XmNc3GRT3ZLeCQPIYbEYGVagH9AJzdmBRvxgFiiNpPJaNAjD3NusgCLQ==} + dependencies: + '@improbable-eng/grpc-web': 0.14.1 + '@improbable-eng/grpc-web-node-http-transport': 0.14.1_@improbable-eng+grpc-web@0.14.1 + '@onflow/protobuf': 0.1.8 + '@onflow/rlp': 0.0.3 + '@onflow/util-actor': 0.0.2 + '@onflow/util-address': 0.0.0 + '@onflow/util-invariant': 0.0.0 + '@onflow/util-template': 0.0.1 + deepmerge: 4.2.2 + transitivePeerDependencies: + - google-protobuf + dev: false + + /@onflow/types/0.0.4: + resolution: {integrity: sha512-47r0qTM45mR7FSvyEE0njGljkpgy3MCf/2W82pfZ/PTFGWr1nsGV/4j2bUfK9Sry4Ymz2W20iRZVP3xpqOhqGw==} + dev: false + + /@onflow/types/0.0.5: + resolution: {integrity: sha512-Pgh3hz3Cr8KPpkaDd1E3FdQRASGqpfA1NK7dtgz+6xdTdESeqU2z0ksocrOdfy9ikRvKt4RyFmDuXPx2CVbjuQ==} + dev: false + + /@onflow/util-actor/0.0.2: + resolution: {integrity: sha512-NV3zPXQue3FqVgcIIMo6ifJOiP3hVSQTaR4ZrWLFU5iAZ/L73cTtBMbCB4BUFOe20ALtF2c9PFmpNVowCYV+nw==} + dependencies: + queue-microtask: 1.1.2 + dev: false + + /@onflow/util-address/0.0.0: + resolution: {integrity: sha512-Lzbw/wV3O1fmfXYF2q6iGLgHz/7ATsLXOHceP5tzeEAKNf+srdtTNJv5jhNGhpFFAtQ6TcomXURVMhUg+/4YbA==} + dev: false + + /@onflow/util-invariant/0.0.0: + resolution: {integrity: sha512-ZCt+NqLdeHt9tZhb0DGxo6iSIS9oNUpLkd0PEMzUYUHr4UwrUO7VruV1AUW3PaF9V78DZ13fNZUiQEzdF76O/w==} + dev: false + + /@onflow/util-template/0.0.1: + resolution: {integrity: sha512-qlJ0oq+QujnZRCOGYaw5OKSDpiDIOpwQMYlMe4Mbz//Wn+LOmUghoKZGmRP+YCgp7BJ4aB6AWW/7kL83NDy50A==} + dev: false + + /@onflow/util-uid/0.0.1: + resolution: {integrity: sha512-SzBscBdyn1Zoks0Wo/w7J/Ds9IZ/T+KM/wyWMwWla4PnxwBFviy1BytEQY+sM5q1UNOvaGWgGEoRmH/oOCcglA==} + dev: false + /@openzeppelin/contracts/3.4.1-solc-0.7-2: resolution: {integrity: sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q==} dev: false @@ -12009,6 +12158,10 @@ packages: /brorand/1.1.0: resolution: {integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=} + /browser-headers/0.4.1: + resolution: {integrity: sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==} + dev: false + /browser-process-hrtime/1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} @@ -13789,7 +13942,6 @@ packages: /deepmerge/4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} engines: {node: '>=0.10.0'} - dev: true /default-compare/1.0.0: resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} @@ -16409,6 +16561,10 @@ packages: sparkles: 1.0.1 dev: true + /google-protobuf/3.19.1: + resolution: {integrity: sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==} + dev: false + /got/7.1.0: resolution: {integrity: sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==} engines: {node: '>=4'} @@ -21411,6 +21567,10 @@ packages: deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: true + /queue-microtask/1.1.2: + resolution: {integrity: sha512-F9wwNePtXrzZenAB3ax0Y8TSKGvuB7Qw16J30hspEUTbfUM+H827XyN3rlpwhVmtm5wuZtbKIHjOnwDn7MUxWQ==} + dev: false + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true From 7efdedd6a4000e0c6225ed4f2e0752fb2f80d2a0 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 03:21:58 +0800 Subject: [PATCH 31/41] refactor: the same progress to select mask wallet --- .../InjectedComponents/ToolboxUnstyled.tsx | 1 - .../src/components/shared/WalletStatusBox.tsx | 8 +---- .../EthereumServices/provider.ts | 12 +++---- .../providers/{Mask.ts => MaskWallet.ts} | 31 ++++++++++++++----- .../providers/WalletConnect.ts | 6 ++-- .../EthereumServices/web3.ts | 2 +- .../pages/Wallet/SelectWallet/index.tsx | 14 ++++++--- .../UI/components/ProviderIconClickBait.tsx | 31 ++++++++----------- .../SNSAdaptor/ConnectWalletDialog/index.tsx | 3 +- .../PluginNetworkWatcher.tsx | 20 ------------ .../PluginProviderRender.tsx | 5 +-- .../SelectProviderDialog/ProviderIcon.tsx | 3 +- .../SNSAdaptor/SelectProviderDialog/index.tsx | 28 +++++++++-------- .../Wallet/SNSAdaptor/SelectWalletDialog.tsx | 2 +- .../src/plugins/Wallet/services/account.ts | 12 +++++++ packages/plugin-infra/src/web3-types.ts | 2 ++ .../UI/components/ProviderIconClickBait.tsx | 10 +++--- packages/web3-shared/evm/pipes/index.ts | 2 +- 18 files changed, 100 insertions(+), 92 deletions(-) rename packages/mask/src/extension/background-script/EthereumServices/providers/{Mask.ts => MaskWallet.ts} (65%) delete mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 745d9b081ec2..e93564dd70b8 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -27,7 +27,6 @@ import { useActivatedPluginsSNSAdaptor, useNetworkDescriptor, useProviderDescriptor, - useProviderType, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' import { Image } from '../shared/Image' diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index 53bd39bc330b..73c7814d8dc5 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -2,13 +2,7 @@ import { useCallback } from 'react' import { useCopyToClipboard } from 'react-use' import { Copy, ExternalLink } from 'react-feather' import classNames from 'classnames' -import { - ProviderType, - resolveAddressLinkOnExplorer, - useWallet, - useChainId, - resolveProviderName, -} from '@masknet/web3-shared-evm' +import { ProviderType, resolveAddressLinkOnExplorer, useWallet, useChainId } from '@masknet/web3-shared-evm' import { Button, Link, Typography } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' import { useNetworkDescriptor, useProviderDescriptor, useProviderType } from '@masknet/plugin-infra' diff --git a/packages/mask/src/extension/background-script/EthereumServices/provider.ts b/packages/mask/src/extension/background-script/EthereumServices/provider.ts index b402887a6e94..17526161854d 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/provider.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/provider.ts @@ -1,6 +1,6 @@ import { first } from 'lodash-es' -import type { ChainId, ProviderType } from '@masknet/web3-shared-evm' -import * as MaskWallet from './providers/Mask' +import type { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-evm' +import * as MaskWallet from './providers/MaskWallet' import * as MetaMask from './providers/MetaMask' import * as WalletConnect from './providers/WalletConnect' import * as CustomNetwork from './providers/CustomNetwork' @@ -49,16 +49,16 @@ export async function cancelWalletConnect() { } //#endregion -export async function connectMetaMask() { - const { accounts, chainId } = await MetaMask.requestAccounts() +export async function connectMaskWallet(networkType: NetworkType) { + const { accounts, chainId } = await MaskWallet.requestAccounts(networkType) return { account: first(accounts), chainId, } } -export async function connectMask() { - const { accounts, chainId } = await MaskWallet.requestAccounts() +export async function connectMetaMask() { + const { accounts, chainId } = await MetaMask.requestAccounts() return { account: first(accounts), chainId, diff --git a/packages/mask/src/extension/background-script/EthereumServices/providers/Mask.ts b/packages/mask/src/extension/background-script/EthereumServices/providers/MaskWallet.ts similarity index 65% rename from packages/mask/src/extension/background-script/EthereumServices/providers/Mask.ts rename to packages/mask/src/extension/background-script/EthereumServices/providers/MaskWallet.ts index f31888252b27..a3b00273ff8f 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/providers/Mask.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/providers/MaskWallet.ts @@ -1,8 +1,10 @@ import MaskWallet from 'web3' import type { HttpProvider } from 'web3-core' -import { ChainId, getChainRPC } from '@masknet/web3-shared-evm' +import { PopupRoutes } from '@masknet/shared-base' +import { ChainId, getChainIdFromNetworkType, getChainRPC, NetworkType } from '@masknet/web3-shared-evm' import { currentChainIdSettings } from '../../../../plugins/Wallet/settings' -import { getWallets } from '../../../../plugins/Wallet/services' +import { getWallets, selectAccountPrepare } from '../../../../plugins/Wallet/services' +import { openPopupWindow } from '../../HelperService' //#region providers const providerPool = new Map() @@ -64,11 +66,24 @@ export function createWeb3({ } //#endregion -export async function requestAccounts() { +export async function requestAccounts(networkType: NetworkType) { const wallets = await getWallets() - const accounts = wallets.filter((x) => x.storedKeyInfo).map((y) => y.address) - return { - accounts, - chainId: currentChainIdSettings.value, - } + return new Promise<{ + chainId: ChainId + accounts: string[] + }>(async (resolve, reject) => { + try { + await selectAccountPrepare((accounts, chainId) => { + resolve({ + chainId, + accounts, + }) + }) + await openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { + chainId: getChainIdFromNetworkType(networkType), + }) + } catch { + reject(new Error('Failed to connect to Mask Network.')) + } + }) } diff --git a/packages/mask/src/extension/background-script/EthereumServices/providers/WalletConnect.ts b/packages/mask/src/extension/background-script/EthereumServices/providers/WalletConnect.ts index a905e2a72c1b..ea4ccd0adf11 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/providers/WalletConnect.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/providers/WalletConnect.ts @@ -1,9 +1,9 @@ -import type { JsonRpcResponse } from 'web3-core-helpers' import { first } from 'lodash-es' +import type { JsonRpcResponse } from 'web3-core-helpers' import WalletConnect from '@walletconnect/client' import type { IJsonRpcRequest } from '@walletconnect/types' import { ProviderType, ChainId } from '@masknet/web3-shared-evm' -import * as Maskbook from './Mask' +import * as MaskWallet from './MaskWallet' import { resetAccount, updateAccount } from '../../../../plugins/Wallet/services' import { currentChainIdSettings, currentProviderSettings } from '../../../../plugins/Wallet/settings' @@ -53,7 +53,7 @@ export async function sendCustomRequest(payload: IJsonRpcRequest) { // Wrap promise as PromiEvent because WalletConnect returns transaction hash only // docs: https://docs.walletconnect.org/client-api export function createWeb3({ chainId = currentChainIdSettings.value }: { chainId?: ChainId } = {}) { - return Maskbook.createWeb3({ + return MaskWallet.createWeb3({ chainId, }) } diff --git a/packages/mask/src/extension/background-script/EthereumServices/web3.ts b/packages/mask/src/extension/background-script/EthereumServices/web3.ts index 62ec3197d925..3335f930a217 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/web3.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/web3.ts @@ -1,6 +1,6 @@ import { ProviderType } from '@masknet/web3-shared-evm' import { unreachable } from '@dimensiondev/kit' -import * as MaskWallet from './providers/Mask' +import * as MaskWallet from './providers/MaskWallet' import * as MetaMask from './providers/MetaMask' import * as WalletConnect from './providers/WalletConnect' import * as Injected from './providers/Injected' diff --git a/packages/mask/src/extension/popups/pages/Wallet/SelectWallet/index.tsx b/packages/mask/src/extension/popups/pages/Wallet/SelectWallet/index.tsx index dda5efc29888..9be59c85a9d9 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/SelectWallet/index.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/SelectWallet/index.tsx @@ -128,7 +128,8 @@ const SelectWallet = memo(() => { const search = new URLSearchParams(location.search) - const chainId = Number.parseInt(search.get('chainId') ?? '0', 10) as ChainId + const chainIdSearched = search.get('chainId') + const chainId = chainIdSearched ? (Number.parseInt(chainIdSearched, 10) as ChainId) : undefined // Swap page also uses SelectWallet, but changing wallet in Swap page // should not affect other pages, for example, dashboard. // So we make Swap page 'internal' for popups @@ -143,7 +144,10 @@ const SelectWallet = memo(() => { [copyToClipboard], ) - const handleCancel = useCallback(() => Services.Helper.removePopupWindow(), []) + const handleCancel = useCallback(async () => { + await WalletRPC.selectAccount([], ChainId.Mainnet) + await Services.Helper.removePopupWindow() + }, []) const handleConfirm = useCallback(async () => { await WalletRPC.updateMaskAccount({ @@ -157,7 +161,9 @@ const SelectWallet = memo(() => { providerType: ProviderType.MaskWallet, }) } - + if (chainId) { + await WalletRPC.selectAccount([selected], chainId) + } return Services.Helper.removePopupWindow() }, [chainId, selected, isInternal]) @@ -165,7 +171,7 @@ const SelectWallet = memo(() => { if (!selected && wallets.length) setSelected(first(wallets)?.address ?? '') }, [selected, wallets]) - return chainIdValid ? ( + return chainId && chainIdValid ? ( <>
      diff --git a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx index 1307c689a10c..83c93a6d8dbb 100644 --- a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx +++ b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx @@ -1,16 +1,8 @@ import { useCallback, cloneElement, isValidElement } from 'react' import { unreachable } from '@dimensiondev/kit' import type { Web3Plugin } from '@masknet/plugin-infra' -import { PopupRoutes } from '@masknet/shared-base' import { useRemoteControlledDialog } from '@masknet/shared' -import { - getChainIdFromNetworkType, - NetworkType, - ProviderType, - resolveProviderDownloadLink, - useWallets, -} from '@masknet/web3-shared-evm' -import Services from '../../../../extension/service' +import { NetworkType, ProviderType, resolveProviderDownloadLink, useWallets } from '@masknet/web3-shared-evm' import { WalletMessages } from '../../../Wallet/messages' import { useInjectedProviderReady, useInjectedProviderType } from '../../hooks' @@ -18,9 +10,10 @@ export interface ProviderIconClickBaitProps { network: Web3Plugin.NetworkDescriptor provider: Web3Plugin.ProviderDescriptor children?: React.ReactNode + onClick?: () => void } -export function ProviderIconClickBait({ network, provider, children }: ProviderIconClickBaitProps) { +export function ProviderIconClickBait({ network, provider, children, onClick }: ProviderIconClickBaitProps) { //#region connect wallet dialog const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( WalletMessages.events.connectWalletDialogUpdated, @@ -34,9 +27,13 @@ export function ProviderIconClickBait({ network, provider, children }: ProviderI const injectedProviderType = useInjectedProviderType() const injectedProviderReady = useInjectedProviderReady() - const onClick = useCallback(async () => { + const onClickProvider = useCallback(async () => { // open the download page - if ([ProviderType.MetaMask, ProviderType.Coin98, ProviderType.WalletLink, ProviderType.MathWallet].includes(providerType)) { + if ( + [ProviderType.MetaMask, ProviderType.Coin98, ProviderType.WalletLink, ProviderType.MathWallet].includes( + providerType, + ) + ) { if (!injectedProviderReady || providerType !== injectedProviderType) { const downloadLink = resolveProviderDownloadLink(providerType) if (downloadLink) window.open(downloadLink, '_blank', 'noopener noreferrer') @@ -46,10 +43,6 @@ export function ProviderIconClickBait({ network, provider, children }: ProviderI switch (providerType) { case ProviderType.MaskWallet: - await Services.Helper.openPopupWindow(wallets.length > 0 ? PopupRoutes.SelectWallet : undefined, { - chainId: getChainIdFromNetworkType(networkType), - }) - break case ProviderType.MetaMask: case ProviderType.WalletConnect: case ProviderType.Coin98: @@ -66,7 +59,9 @@ export function ProviderIconClickBait({ network, provider, children }: ProviderI default: unreachable(providerType) } - }, [networkType, providerType, wallets, injectedProviderReady, injectedProviderType]) + + onClick?.() + }, [networkType, providerType, wallets, injectedProviderReady, injectedProviderType, onClick]) return ( <> @@ -74,7 +69,7 @@ export function ProviderIconClickBait({ network, provider, children }: ProviderI ? cloneElement(children, { ...children.props, ...{ - onClick, + onClick: onClickProvider, }, }) : children} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx index ffdce3cf1b52..1c2b92b221ce 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx @@ -66,7 +66,8 @@ export function ConnectWalletDialog(props: ConnectWalletDialogProps) { switch (providerType) { case ProviderType.MaskWallet: - throw new Error('Not necessary!') + ;({ account, chainId } = await Services.Ethereum.connectMaskWallet(networkType)) + break case ProviderType.MetaMask: ;({ account, chainId } = await Services.Ethereum.connectMetaMask()) break diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx deleted file mode 100644 index 9446de0228e9..000000000000 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginNetworkWatcher.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { Web3Plugin } from '@masknet/plugin-infra' -import { useEffect } from 'react' -import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' - -export interface PluginNetworkWatcherProps { - network?: Web3Plugin.NetworkDescriptor - expectedPluginID: string - expectedNetworkID: string -} - -export function PluginNetworkWatcher({ network, expectedPluginID, expectedNetworkID }: PluginNetworkWatcherProps) { - useEffect(() => { - const matched = - network && network.networkSupporterPluginID === expectedPluginID && network.ID === expectedNetworkID - if (!matched) return - pluginIDSettings.value = expectedPluginID - networkIDSettings.value = expectedNetworkID - }, [network, expectedPluginID, expectedNetworkID]) - return null -} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx index b00cdd92e30f..b0444b12ddde 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/PluginProviderRender.tsx @@ -131,11 +131,12 @@ export function PluginProviderRender({ {providers .filter((x) => x.providerAdaptorPluginID === undeterminedPluginID) .map((provider) => ( - + {ProviderIconClickBait ? ( x.ID === undeterminedNetworkID)!} - provider={provider}> + provider={provider} + onClick={onSubmit}> ) : ( diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx index 1e67ecd1444f..424727b60456 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/ProviderIcon.tsx @@ -1,5 +1,4 @@ -import { makeStyles } from '@masknet/theme' -import { getMaskColor } from '@masknet/theme' +import { makeStyles, getMaskColor } from '@masknet/theme' import { Typography, Card, ButtonBase, ButtonBaseProps } from '@mui/material' const useStyles = makeStyles()((theme) => ({ diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index bf42635912bc..55e34127333b 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { makeStyles } from '@masknet/theme' import { DialogContent } from '@mui/material' import { useRemoteControlledDialog, useValueRef } from '@masknet/shared' @@ -14,7 +14,6 @@ import { WalletMessages } from '../../messages' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { hasNativeAPI, nativeAPI } from '../../../../utils' import { PluginProviderRender } from './PluginProviderRender' -import { PluginNetworkWatcher } from './PluginNetworkWatcher' import { networkIDSettings, pluginIDSettings } from '../../../../settings/settings' const useStyles = makeStyles()((theme) => ({ @@ -56,21 +55,24 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const networks = getRegisteredWeb3Networks() const providers = getRegisteredWeb3Providers() + const onSubmit = useCallback(() => { + const matched = + undeterminedNetwork && + undeterminedNetwork.networkSupporterPluginID === undeterminedPluginID && + undeterminedNetwork.ID === undeterminedNetworkID + + if (matched) { + pluginIDSettings.value = undeterminedPluginID + networkIDSettings.value = undeterminedNetworkID + } + closeDialog() + }, [undeterminedNetwork, undeterminedPluginID, undeterminedNetworkID, closeDialog]) + const { NetworkIconClickBait, ProviderIconClickBait } = undeterminedWeb3UI?.SelectProviderDialog ?? {} // not available for the native app if (hasNativeAPI) return null - // if the dialog closes then start capturing the currently selected network - if (!open) - return ( - - ) - return ( @@ -83,7 +85,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { setUndeterminedNetworkID={setUndeterminedNetworkID} NetworkIconClickBait={NetworkIconClickBait} ProviderIconClickBait={ProviderIconClickBait} - onSubmit={closeDialog} + onSubmit={onSubmit} /> diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx index ce2c592b1f6a..d0647dcc982d 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx @@ -4,8 +4,8 @@ import { Button, DialogActions, DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' import { isEnvironment, Environment } from '@dimensiondev/holoflows-kit' import { ProviderType, useWallets, useWallet, NetworkType } from '@masknet/web3-shared-evm' -import { delay, useI18N } from '../../../utils' import { DashboardRoutes, useRemoteControlledDialog, useStylesExtends } from '@masknet/shared' +import { delay, useI18N } from '../../../utils' import { WalletMessages, WalletRPC } from '../messages' import { WalletInList } from '../../../components/shared/SelectWallet/WalletInList' import Services from '../../../extension/service' diff --git a/packages/mask/src/plugins/Wallet/services/account.ts b/packages/mask/src/plugins/Wallet/services/account.ts index 3cfe0f9c6508..fa90ce23aa42 100644 --- a/packages/mask/src/plugins/Wallet/services/account.ts +++ b/packages/mask/src/plugins/Wallet/services/account.ts @@ -97,6 +97,18 @@ export async function resetAccount( if (providerType) currentProviderSettings.value = providerType } +//#region select wallet with popups +let callbackMemorized: (accounts: string[], chainId: ChainId) => void | undefined + +export async function selectAccountPrepare(callback: (accounts: string[], chainId: ChainId) => void) { + callbackMemorized = callback +} + +export async function selectAccount(accounts: string[], chainId: ChainId) { + callbackMemorized?.(accounts, chainId) +} +//#endregion + export async function setDefaultWallet() { if (currentAccountSettings.value) return const wallets = await getWallets() diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 0f21be6bb90a..7223e1c5eeb1 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -229,11 +229,13 @@ export declare namespace Web3Plugin { export interface NetworkIconClickBaitProps { network: NetworkDescriptor children?: React.ReactNode + onClick?: () => void } export interface ProviderIconClickBaitProps { network: NetworkDescriptor provider: ProviderDescriptor children?: React.ReactNode + onClick?: () => void } export interface SelectProviderDialogBait { /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ diff --git a/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx index 5b5656e398db..6de8cf5eb8f8 100644 --- a/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx +++ b/packages/plugins/Flow/src/UI/components/ProviderIconClickBait.tsx @@ -6,17 +6,19 @@ export interface ProviderIconClickBaitProps { network: Web3Plugin.NetworkDescriptor provider: Web3Plugin.ProviderDescriptor children?: React.ReactNode + onClick?: () => void } -export function ProviderIconClickBait({ network, provider, children }: ProviderIconClickBaitProps) { +export function ProviderIconClickBait({ network, provider, children, onClick }: ProviderIconClickBaitProps) { const networkType = network.type as NetworkType const providerType = network.type as ProviderType const fcl = useFCL() const onLogIn = useCallback(() => fcl.logIn(), [fcl]) - const onClick = useCallback(() => { + const onClickProvider = useCallback(() => { onLogIn() - }, [networkType, providerType, onLogIn]) + onClick?.() + }, [networkType, providerType, onLogIn, onClick]) return ( <> @@ -24,7 +26,7 @@ export function ProviderIconClickBait({ network, provider, children }: ProviderI ? cloneElement(children, { ...children.props, ...{ - onClick, + onClick: onClickProvider, }, }) : children} diff --git a/packages/web3-shared/evm/pipes/index.ts b/packages/web3-shared/evm/pipes/index.ts index d78c87ea08a0..3560e34a0bcc 100644 --- a/packages/web3-shared/evm/pipes/index.ts +++ b/packages/web3-shared/evm/pipes/index.ts @@ -14,7 +14,7 @@ import { getChainDetailed, createLookupTableResolver } from '../utils' export const resolveProviderName = createLookupTableResolver( { - [ProviderType.MaskWallet]: 'Mask', + [ProviderType.MaskWallet]: 'Mask Network', [ProviderType.MetaMask]: 'MetaMask', [ProviderType.WalletConnect]: 'WalletConnect', [ProviderType.CustomNetwork]: 'CustomNetwork', From a87bdfcaea6d8c13a086df9ac900053f9bd2027c Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 03:26:45 +0800 Subject: [PATCH 32/41] refactor: remove edit name link --- .../mask/src/components/shared/WalletStatusBox.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index 73c7814d8dc5..db216c6a9f27 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -72,7 +72,6 @@ export function WalletStatusBox() { const chainId = useChainId() const selectedWallet = useWallet() - const { setDialog: setRenameDialog } = useRemoteControlledDialog(WalletMessages.events.walletRenameDialogUpdated) const providerType = useProviderType() const providerDescriptor = useProviderDescriptor() @@ -137,16 +136,6 @@ export function WalletStatusBox() {
      {providerDescriptor?.name} - { - setRenameDialog({ - open: true, - wallet: selectedWallet, - }) - }} - />
      From 1356c1b96d75ab0fc19ce7597a5f0f30057414b3 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 04:04:02 +0800 Subject: [PATCH 33/41] refactor: format ethereum address --- .../InjectedComponents/ToolboxUnstyled.tsx | 6 +- .../src/components/shared/WalletStatusBox.tsx | 22 +++++--- .../src/plugins/EVM/UI/Web3State/index.ts | 7 ++- .../SNSAdaptor/SelectProviderDialog/index.tsx | 4 +- packages/plugin-infra/package.json | 1 + packages/plugin-infra/src/web3-types.ts | 16 ++++-- packages/plugin-infra/src/web3/Context.tsx | 4 +- packages/plugin-infra/src/web3/index.ts | 3 + packages/plugin-infra/src/web3/useAccount.ts | 6 ++ .../plugin-infra/src/web3/useWeb3State.ts | 7 +++ packages/plugin-infra/src/web3/useWeb3UI.ts | 7 +++ packages/shared/src/wallet/FormatAddress.tsx | 13 +++++ packages/shared/src/wallet/FormatBalance.tsx | 32 +++++++++++ packages/shared/src/wallet/FormatCurrency.tsx | 18 ++++++ packages/shared/src/wallet/components.tsx | 55 ------------------- packages/shared/src/wallet/index.ts | 4 +- pnpm-lock.yaml | 2 + 17 files changed, 133 insertions(+), 74 deletions(-) create mode 100644 packages/plugin-infra/src/web3/useWeb3State.ts create mode 100644 packages/plugin-infra/src/web3/useWeb3UI.ts create mode 100644 packages/shared/src/wallet/FormatAddress.tsx create mode 100644 packages/shared/src/wallet/FormatBalance.tsx create mode 100644 packages/shared/src/wallet/FormatCurrency.tsx delete mode 100644 packages/shared/src/wallet/components.tsx diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index e93564dd70b8..c4ce763364cb 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -18,7 +18,6 @@ import { useChainDetailed, useChainIdValid, useWallet, - formatEthereumAddress, TransactionStatusType, useChainId, } from '@masknet/web3-shared-evm' @@ -27,6 +26,7 @@ import { useActivatedPluginsSNSAdaptor, useNetworkDescriptor, useProviderDescriptor, + useWeb3State, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' import { Image } from '../shared/Image' @@ -188,6 +188,8 @@ function useToolbox() { const chainDetailed = useChainDetailed() const operatingSupportedChainMapping = useActivatedPluginSNSAdaptor_withSupportOperateChain(chainId) + const { Utils } = useWeb3State() + //#region recent pending transactions const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) //#endregion @@ -302,7 +304,7 @@ function useToolbox() { function renderButtonText() { if (!account) return t('plugin_wallet_on_connect') if (!chainIdValid) return t('plugin_wallet_wrong_network') - if (pendingTransactions.length <= 0) return formatEthereumAddress(account, 4) + if (pendingTransactions.length <= 0) return Utils?.formatAddress?.(account, 4) ?? account return ( <> diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index db216c6a9f27..6597a9f531f8 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -2,10 +2,17 @@ import { useCallback } from 'react' import { useCopyToClipboard } from 'react-use' import { Copy, ExternalLink } from 'react-feather' import classNames from 'classnames' -import { ProviderType, resolveAddressLinkOnExplorer, useWallet, useChainId } from '@masknet/web3-shared-evm' +import { ProviderType, resolveAddressLinkOnExplorer } from '@masknet/web3-shared-evm' import { Button, Link, Typography } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' -import { useNetworkDescriptor, useProviderDescriptor, useProviderType } from '@masknet/plugin-infra' +import { + useAccount, + useWeb3State, + useChainId, + useNetworkDescriptor, + useProviderDescriptor, + useProviderType, +} from '@masknet/plugin-infra' import { FormattedAddress, useRemoteControlledDialog, useSnackbarCallback, WalletIcon } from '@masknet/shared' import { WalletMessages } from '../../plugins/Wallet/messages' import { useI18N } from '../../utils' @@ -71,18 +78,19 @@ export function WalletStatusBox() { const { classes } = useStyles() const chainId = useChainId() - const selectedWallet = useWallet() + const account = useAccount() const providerType = useProviderType() const providerDescriptor = useProviderDescriptor() const networkDescriptor = useNetworkDescriptor() + const { Utils } = useWeb3State() ?? {} //#region copy addr to clipboard const [, copyToClipboard] = useCopyToClipboard() const onCopy = useSnackbarCallback( async (ev: React.MouseEvent) => { ev.stopPropagation() - copyToClipboard(selectedWallet?.address ?? '') + copyToClipboard(account) }, [], undefined, @@ -121,7 +129,7 @@ export function WalletStatusBox() { providerDescriptor, }) - return selectedWallet ? ( + return account ? (
      - + diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index d026f283db2f..5e3f86ceae18 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,5 +1,5 @@ import type { Web3Plugin } from '@masknet/plugin-infra' -import type { Web3ProviderType } from '@masknet/web3-shared-evm' +import { formatBalance, formatCurrency, formatEthereumAddress, Web3ProviderType } from '@masknet/web3-shared-evm' export const Web3State: Web3Plugin.ObjectCapabilities.Capabilities = {} @@ -14,5 +14,10 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, networkType: context.networkType, providerType: context.providerType, } + state.Utils = state.Utils ?? { + formatAddress: formatEthereumAddress, + formatCurrency, + formatBalance, + } return state } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 55e34127333b..df0823fdd377 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -5,9 +5,9 @@ import { useRemoteControlledDialog, useValueRef } from '@masknet/shared' import { getRegisteredWeb3Networks, getRegisteredWeb3Providers, - useActivatedPluginWeb3UI, useNetworkDescriptor, useNetworkType, + useWeb3UI, } from '@masknet/plugin-infra' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' @@ -48,7 +48,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(networkID) - const undeterminedWeb3UI = useActivatedPluginWeb3UI(undeterminedPluginID) + const undeterminedWeb3UI = useWeb3UI(undeterminedPluginID) const undeterminedNetworkType = useNetworkType(undeterminedPluginID) const undeterminedNetwork = useNetworkDescriptor(undeterminedNetworkType, undeterminedPluginID) diff --git a/packages/plugin-infra/package.json b/packages/plugin-infra/package.json index 9125e047d843..c3e203c8a8e6 100644 --- a/packages/plugin-infra/package.json +++ b/packages/plugin-infra/package.json @@ -12,6 +12,7 @@ "@servie/events": "^3.0.0", "@types/use-subscription": "^1.0.0", "async-call-rpc": "^6.0.0", + "bignumber.js": "^9.0.1", "lodash-es": "^4.17.21", "ts-results": "^3.3.0", "unstated-next": "^1.1.0", diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 7223e1c5eeb1..ddaf482696af 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -1,4 +1,5 @@ import type { Subscription } from 'use-subscription' +import type { BigNumber } from 'bignumber.js' import type { Pagination } from './types' import type { Plugin } from '.' @@ -211,10 +212,13 @@ export declare namespace Web3Plugin { ) => Promise[]> } export interface Others { - isChainIdValid: (chainId: number, allowTestnet: boolean) => boolean - getChainDetailed: (chainId: number) => ChainDetailed - getFungibleTokenMetadata: (token: Token) => Promise> - getNonFungibleTokenMetadata: (token: Token) => Promise> + formatAddress?: (address: string, size?: number) => string + formatCurrency?: (value: BigNumber.Value, sign?: string, symbol?: string) => string + formatBalance?: (value: BigNumber.Value, decimals?: number, significant?: number) => string + isChainIdValid?: (chainId: number, allowTestnet: boolean) => boolean + getChainDetailed?: (chainId: number) => ChainDetailed + getFungibleTokenMetadata?: (token: Token) => Promise> + getNonFungibleTokenMetadata?: (token: Token) => Promise> } export interface Capabilities { Shared?: SharedState @@ -237,6 +241,10 @@ export declare namespace Web3Plugin { children?: React.ReactNode onClick?: () => void } + export interface AddressFormatterProps { + address: string + size?: number + } export interface SelectProviderDialogBait { /** This UI will receive network icon as children component, and the plugin may hook click handle on it. */ NetworkIconClickBait?: Plugin.InjectUIReact diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index e2fe502d7bbb..f9aa5b8bc52f 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -49,8 +49,8 @@ function usePluginWeb3State(pluginID: string, context: Record string +} + +export const FormattedAddress: FC = ({ address, size, formatter = identity }) => { + if (!address) return null + return {formatter(address, size)} +} diff --git a/packages/shared/src/wallet/FormatBalance.tsx b/packages/shared/src/wallet/FormatBalance.tsx new file mode 100644 index 000000000000..f5383cf24a00 --- /dev/null +++ b/packages/shared/src/wallet/FormatBalance.tsx @@ -0,0 +1,32 @@ +import { FC, Fragment } from 'react' +import type { BigNumber } from 'bignumber.js' +import { makeStyles } from '@masknet/theme' +import { useStylesExtends } from '../UI/UIHelper/custom-ui-helper' + +const useStyles = makeStyles()((theme) => ({ + balance: { + marginRight: theme.spacing(0.5), + }, +})) + +export interface FormattedBalanceProps extends withClasses<'balance' | 'symbol'> { + value: BigNumber.Value | undefined + decimals?: number + significant?: number + symbol?: string + formatter?: (value: BigNumber.Value, decimals?: number, significant?: number) => string +} + +export const FormattedBalance: FC = (props) => { + const { value, decimals, significant, symbol, formatter = (value) => value } = props + const formatted = formatter(value ?? '0', decimals, significant) + const classes = useStylesExtends(useStyles(), props) + if (symbol) + return ( + + {formatted} + {symbol} + + ) + return {formatted} +} diff --git a/packages/shared/src/wallet/FormatCurrency.tsx b/packages/shared/src/wallet/FormatCurrency.tsx new file mode 100644 index 000000000000..ab9e511d025b --- /dev/null +++ b/packages/shared/src/wallet/FormatCurrency.tsx @@ -0,0 +1,18 @@ +import { FC, Fragment } from 'react' +import type { BigNumber } from 'bignumber.js' + +export interface FormattedCurrencyProps { + sign?: string + symbol?: string + value: BigNumber.Value + formatter?: (value: BigNumber.Value, sign?: string, symbol?: string) => string +} + +export const FormattedCurrency: FC = ({ + value, + sign, + symbol, + formatter = (value, sign, symbol) => `${sign} ${value} ${symbol?.toUpperCase()}`.trim(), +}) => { + return {formatter(value, sign, symbol)} +} diff --git a/packages/shared/src/wallet/components.tsx b/packages/shared/src/wallet/components.tsx deleted file mode 100644 index a9dd473cf52a..000000000000 --- a/packages/shared/src/wallet/components.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import type { BigNumber } from 'bignumber.js' -import { FC, Fragment } from 'react' -import { makeStyles } from '@masknet/theme' -import { formatBalance, formatCurrency, formatEthereumAddress } from '@masknet/web3-shared-evm' -import { useStylesExtends } from '../UI/UIHelper/custom-ui-helper' - -const useStyles = makeStyles()((theme) => ({ - balance: { - marginRight: theme.spacing(0.5), - }, -})) - -export interface FormattedBalanceProps extends withClasses<'balance' | 'symbol'> { - value: BigNumber.Value | undefined - decimals?: number - significant?: number - symbol?: string -} - -export const FormattedBalance: FC = (props) => { - const { value, decimals, significant, symbol } = props - const formatted = formatBalance(value, decimals, significant) - const classes = useStylesExtends(useStyles(), props) - if (symbol) - return ( - - {formatted} - {symbol} - - ) - return {formatted} -} - -export interface FormattedCurrencyProps { - sign?: string - symbol?: string - value: BigNumber.Value -} - -export const FormattedCurrency: FC = ({ value, sign, symbol }) => { - const formatted = formatCurrency(value, sign) - if (symbol) return {`${formatted} ${symbol}`} - return {formatted} -} - -interface FormattedEthereumAddressProps { - address?: string - size?: number -} - -export const FormattedAddress: FC = ({ address, size }) => { - if (!address) return null - const formatted = formatEthereumAddress(address, size) - return {formatted} -} diff --git a/packages/shared/src/wallet/index.ts b/packages/shared/src/wallet/index.ts index cb64ac1b52aa..46f88bb50510 100644 --- a/packages/shared/src/wallet/index.ts +++ b/packages/shared/src/wallet/index.ts @@ -1 +1,3 @@ -export * from './components' +export * from './FormatBalance' +export * from './FormatAddress' +export * from './FormatCurrency' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d79b2a4a94c..29e6dfe18efc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -552,6 +552,7 @@ importers: '@servie/events': ^3.0.0 '@types/use-subscription': ^1.0.0 async-call-rpc: ^6.0.0 + bignumber.js: ^9.0.1 lodash-es: ^4.17.21 ts-results: ^3.3.0 unstated-next: ^1.1.0 @@ -563,6 +564,7 @@ importers: '@servie/events': 3.0.0 '@types/use-subscription': 1.0.0 async-call-rpc: 6.0.0 + bignumber.js: 9.0.1 lodash-es: 4.17.21 ts-results: 3.3.0 unstated-next: 1.1.0 From 17f782df28242b7cde8f3d544ed04bb9fb6e48e5 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 04:26:21 +0800 Subject: [PATCH 34/41] chore: the wallet address in flow chain --- .../InjectedComponents/ToolboxUnstyled.tsx | 13 ++++--------- packages/plugin-infra/src/web3/useAccount.ts | 6 ------ packages/plugins/Flow/src/UI/Web3State/index.ts | 17 +++++++++++++---- packages/plugins/Flow/src/helpers/formatter.ts | 5 +++++ packages/plugins/Flow/src/helpers/index.ts | 2 +- packages/web3-shared/evm/utils/formatter.ts | 2 +- 6 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 packages/plugins/Flow/src/helpers/formatter.ts diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index c4ce763364cb..bec201193226 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -12,20 +12,15 @@ import { ListItemText as MuiListItemText, Box, } from '@mui/material' -import { - useAccount, - useChainColor, - useChainDetailed, - useChainIdValid, - useWallet, - TransactionStatusType, - useChainId, -} from '@masknet/web3-shared-evm' +import { useChainColor, useChainDetailed, useWallet, TransactionStatusType } from '@masknet/web3-shared-evm' import { useActivatedPluginSNSAdaptor_withSupportOperateChain, useActivatedPluginsSNSAdaptor, useNetworkDescriptor, useProviderDescriptor, + useAccount, + useChainId, + useChainIdValid, useWeb3State, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' diff --git a/packages/plugin-infra/src/web3/useAccount.ts b/packages/plugin-infra/src/web3/useAccount.ts index deac633aaf5b..5f5a3656711c 100644 --- a/packages/plugin-infra/src/web3/useAccount.ts +++ b/packages/plugin-infra/src/web3/useAccount.ts @@ -6,11 +6,5 @@ import { usePluginWeb3StateContext } from './Context' */ export function useAccount(pluginID?: string) { const { account, wallets } = usePluginWeb3StateContext(pluginID) - - console.log({ - account, - wallets, - }) - return process.env.architecture === 'app' ? first(wallets)?.address ?? '' : account } diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index 037aa4ba731c..1918bab6c6b1 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -4,6 +4,7 @@ import type { Web3Plugin } from '@masknet/plugin-infra' import { getAuthConstants } from '@masknet/web3-shared-flow/constants' import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-flow' import { createConstantSubscription, createSubscriptionFromAsync } from '@masknet/shared-base' +import { formatAddress } from '../../helpers' function createClient(chainId: ChainId) { const authConstants = getAuthConstants(chainId) @@ -17,7 +18,7 @@ function createClient(chainId: ChainId) { return fcl } -function createCurrentUserSubscription(chainId: ChainId, fallback: T, getter: (client: typeof fcl) => T) { +function createCurrentUserSubscription(chainId: ChainId, fallback: T, getter: (client: typeof fcl) => Promise) { const client = createClient(chainId) const listeners: (() => void)[] = [] @@ -37,18 +38,26 @@ function createCurrentUserSubscription(chainId: ChainId, fallback: T, getter: ) } -function createWeb3State() { +function createWeb3State(): Web3Plugin.ObjectCapabilities.Capabilities { const chainId = ChainId.Testnet return { Shared: { allowTestnet: createConstantSubscription(false), + account: createCurrentUserSubscription(chainId, '', async (client) => { + const currentUser = await client.currentUser().snapshot() + return currentUser.addr ?? '' + }), chainId: createConstantSubscription(chainId), networkType: createConstantSubscription(NetworkType.Flow), - providerType: createCurrentUserSubscription(chainId, undefined, (client) => { + providerType: createCurrentUserSubscription(chainId, undefined, async (client) => { return client.currentUser().snapshot() ? ProviderType.Blocto : undefined }), }, + Utils: { + formatAddress, + isChainIdValid: () => true, + }, } } -export const Web3State: Web3Plugin.ObjectCapabilities.Capabilities = createWeb3State() +export const Web3State = createWeb3State() diff --git a/packages/plugins/Flow/src/helpers/formatter.ts b/packages/plugins/Flow/src/helpers/formatter.ts new file mode 100644 index 000000000000..2c4ccdadf7af --- /dev/null +++ b/packages/plugins/Flow/src/helpers/formatter.ts @@ -0,0 +1,5 @@ +export function formatAddress(address: string, size = 0) { + if (!/0x\w{16}/.test(address)) return address + if (size === 0 || size >= 8) return address + return `${address.substr(0, 2 + size)}...${address.substr(-size)}` +} diff --git a/packages/plugins/Flow/src/helpers/index.ts b/packages/plugins/Flow/src/helpers/index.ts index 336ce12bb910..80c86669067a 100644 --- a/packages/plugins/Flow/src/helpers/index.ts +++ b/packages/plugins/Flow/src/helpers/index.ts @@ -1 +1 @@ -export {} +export * from './formatter' diff --git a/packages/web3-shared/evm/utils/formatter.ts b/packages/web3-shared/evm/utils/formatter.ts index b9e1642e1c03..251c786fa705 100644 --- a/packages/web3-shared/evm/utils/formatter.ts +++ b/packages/web3-shared/evm/utils/formatter.ts @@ -54,7 +54,7 @@ export function formatCurrency(value: BigNumber.Value, sign = '') { export function formatEthereumAddress(address: string, size = 0) { if (!EthereumAddress.isValid(address)) return address const address_ = EthereumAddress.checksumAddress(address) - if (size === 0) return address_ + if (size === 0 || size >= 20) return address_ return `${address_.substr(0, 2 + size)}...${address_.substr(-size)}` } From 30e47f01bda0f7679301e713043a3e5f3ac70b0a Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 04:30:47 +0800 Subject: [PATCH 35/41] chore: evm - chainIdValid --- .../components/InjectedComponents/ToolboxUnstyled.tsx | 1 - packages/mask/src/plugins/EVM/UI/Web3State/index.ts | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index bec201193226..5f111ec69afa 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -182,7 +182,6 @@ function useToolbox() { const chainIdValid = useChainIdValid() const chainDetailed = useChainDetailed() const operatingSupportedChainMapping = useActivatedPluginSNSAdaptor_withSupportOperateChain(chainId) - const { Utils } = useWeb3State() //#region recent pending transactions diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index 5e3f86ceae18..dc32c7f0ca8b 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,5 +1,11 @@ import type { Web3Plugin } from '@masknet/plugin-infra' -import { formatBalance, formatCurrency, formatEthereumAddress, Web3ProviderType } from '@masknet/web3-shared-evm' +import { + formatBalance, + formatCurrency, + formatEthereumAddress, + isChainIdValid, + Web3ProviderType, +} from '@masknet/web3-shared-evm' export const Web3State: Web3Plugin.ObjectCapabilities.Capabilities = {} @@ -18,6 +24,7 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, formatAddress: formatEthereumAddress, formatCurrency, formatBalance, + isChainIdValid, } return state } From 38ea999adbfe5011a2508eb4e16bcb39013f123b Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 04:49:05 +0800 Subject: [PATCH 36/41] fix: a react hook disaster --- .../src/components/shared/WalletStatusBox.tsx | 5 --- packages/web3-shared/evm/hooks/useBalance.ts | 33 +++++++++---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index 6597a9f531f8..bfb9c17bc116 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -124,11 +124,6 @@ export function WalletStatusBox() { openSelectProviderDialog() }, [openSelectProviderDialog]) - console.log({ - networkDescriptor, - providerDescriptor, - }) - return account ? (
      getChainIdFromNetworkType(x as NetworkType)) - const allRequest = !account - ? null - : chainIdList.map(async (chainId) => { - const { RPC } = getRPCConstants(chainId) - const providerURL = first(RPC) - let balance = '0' - if (providerURL) { - web3.setProvider(providerURL) - balance = await web3.eth.getBalance(account) - } - return { balance, chainId } - }) return useAsync(async () => { - if (!allRequest || !account) return null - const balanceList = (await Promise.allSettled(allRequest)) + if (!account) return null + const allRequest = chainIdList.map(async (chainId) => { + const { RPC } = getRPCConstants(chainId) + const providerURL = first(RPC) + let balance = '0' + if (providerURL) { + web3.setProvider(providerURL) + balance = await web3.eth.getBalance(account) + } + return { balance, chainId } + }) + return (await Promise.allSettled(allRequest)) .map((x) => (x.status === 'fulfilled' ? x.value : undefined)) .filter((value) => value) as { balance: string; chainId: ChainId }[] - return balanceList - }, [account, providerType, allRequest]) + }, [account, providerType]) } From 0e80af687a660e20d644c4bf89d23478a33187ce Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 19:02:35 +0800 Subject: [PATCH 37/41] fix: select provider for EVM --- .../src/components/shared/WalletStatusBox.tsx | 2 +- .../mask/src/plugins/EVM/UI/Web3State/index.ts | 6 ++++++ .../ConnectWalletDialog/ConnectionProgress.tsx | 3 ++- packages/plugin-infra/src/web3-types.ts | 3 +++ packages/plugins/Flow/src/UI/Web3State/index.ts | 13 ++++++++++++- .../shared/src/UI/components/WalletIcon/index.tsx | 1 - packages/web3-constants/flow/auth.json | 4 ++-- packages/web3-shared/flow/hooks/useChainId.ts | 2 +- packages/web3-shared/flow/package.json | 3 ++- packages/web3-shared/flow/pipes/index.ts | 15 +++++++++++---- pnpm-lock.yaml | 2 ++ 11 files changed, 42 insertions(+), 12 deletions(-) diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index bfb9c17bc116..a6b726ee847c 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -154,7 +154,7 @@ export function WalletStatusBox() { diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index dc32c7f0ca8b..3bcf67f0c564 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -4,6 +4,9 @@ import { formatCurrency, formatEthereumAddress, isChainIdValid, + resolveAddressLinkOnExplorer, + resolveBlockLinkOnExplorer, + resolveTransactionLinkOnExplorer, Web3ProviderType, } from '@masknet/web3-shared-evm' @@ -24,6 +27,9 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, formatAddress: formatEthereumAddress, formatCurrency, formatBalance, + resolveTransactionLink: resolveTransactionLinkOnExplorer, + resolveAddressLink: resolveAddressLinkOnExplorer, + resolveBlockLink: resolveBlockLinkOnExplorer, isChainIdValid, } return state diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx index 6cdac3deee5d..307bfc01e03e 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx @@ -6,6 +6,7 @@ import { useProviderDescriptor } from '@masknet/plugin-infra' import type { ProviderType } from '@masknet/web3-shared-evm' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { useI18N } from '../../../../utils' +import { PLUGIN_ID } from '../../../EVM/constants' const useStyles = makeStyles()((theme) => ({ content: { @@ -32,7 +33,7 @@ export function ConnectionProgress(props: ConnectionProgressProps) { const { t } = useI18N() const classes = useStylesExtends(useStyles(), props) - const providerDescriptor = useProviderDescriptor(providerType) + const providerDescriptor = useProviderDescriptor(providerType, PLUGIN_ID) return ( diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index ddaf482696af..aa37dca39a13 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -219,6 +219,9 @@ export declare namespace Web3Plugin { getChainDetailed?: (chainId: number) => ChainDetailed getFungibleTokenMetadata?: (token: Token) => Promise> getNonFungibleTokenMetadata?: (token: Token) => Promise> + resolveTransactionLink?: (chainId: number, transactionId: string) => string + resolveAddressLink?: (chainId: number, address: string) => string + resolveBlockLink?: (chainId: number, blockNumber: string) => string } export interface Capabilities { Shared?: SharedState diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index 1918bab6c6b1..f06a74101fe2 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -2,7 +2,14 @@ import { remove } from 'lodash-es' import * as fcl from '@onflow/fcl' import type { Web3Plugin } from '@masknet/plugin-infra' import { getAuthConstants } from '@masknet/web3-shared-flow/constants' -import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-flow' +import { + ChainId, + NetworkType, + ProviderType, + resolveBlockLinkOnExplorer, + resolveTransactionLinkOnExplorer, + resolveAddressLinkOnExplorer, +} from '@masknet/web3-shared-flow' import { createConstantSubscription, createSubscriptionFromAsync } from '@masknet/shared-base' import { formatAddress } from '../../helpers' @@ -14,6 +21,7 @@ function createClient(chainId: ChainId) { 'app.detail.title': authConstants.MASK_APP_TITLE, 'app.detail.icon': authConstants.MASK_APP_ICON, 'challenge.handshake': authConstants.CHALLENGE_HANDSHAKE, + 'discovery.wallet.method': 'HTTP/POST', }) return fcl } @@ -56,6 +64,9 @@ function createWeb3State(): Web3Plugin.ObjectCapabilities.Capabilities { Utils: { formatAddress, isChainIdValid: () => true, + resolveTransactionLink: resolveTransactionLinkOnExplorer, + resolveAddressLink: resolveAddressLinkOnExplorer, + resolveBlockLink: resolveBlockLinkOnExplorer, }, } } diff --git a/packages/shared/src/UI/components/WalletIcon/index.tsx b/packages/shared/src/UI/components/WalletIcon/index.tsx index 5e895274ffb0..5d01c081f8ed 100644 --- a/packages/shared/src/UI/components/WalletIcon/index.tsx +++ b/packages/shared/src/UI/components/WalletIcon/index.tsx @@ -24,7 +24,6 @@ const useStyles = makeStyles()((theme, props) => ({ position: 'absolute', right: -2, bottom: -2, - backgroundColor: '#ffffff', borderRadius: '50%', }, networkIcon: {}, diff --git a/packages/web3-constants/flow/auth.json b/packages/web3-constants/flow/auth.json index 65ad7bd23a6c..e8950d68614d 100644 --- a/packages/web3-constants/flow/auth.json +++ b/packages/web3-constants/flow/auth.json @@ -8,8 +8,8 @@ "Testnet": "https://flow-wallet-testnet.blocto.app/authn" }, "CHALLENGE_HANDSHAKE": { - "Mainnet": "https://flow-wallet.blocto.app/authn", - "Testnet": "https://flow-wallet-testnet.blocto.app/authn" + "Mainnet": "https://flow-wallet.blocto.app/api/flow/authn", + "Testnet": "https://flow-wallet-testnet.blocto.app/api/flow/authn" }, "MASK_APP_TITLE": { "Mainnet": "Mask Network", diff --git a/packages/web3-shared/flow/hooks/useChainId.ts b/packages/web3-shared/flow/hooks/useChainId.ts index 21a4b4e0fedb..d3d2b0c85b6e 100644 --- a/packages/web3-shared/flow/hooks/useChainId.ts +++ b/packages/web3-shared/flow/hooks/useChainId.ts @@ -1,5 +1,5 @@ import { ChainId } from '../types' export function useChainId() { - return ChainId.Testnet + return ChainId.Mainnet } diff --git a/packages/web3-shared/flow/package.json b/packages/web3-shared/flow/package.json index 1614ee07f678..0640fc623ea4 100644 --- a/packages/web3-shared/flow/package.json +++ b/packages/web3-shared/flow/package.json @@ -8,6 +8,7 @@ "@masknet/web3-kit": "workspace:*", "@onflow/fcl": "^0.0.77", "@onflow/types": "^0.0.5", - "react-use": "^17.3.1" + "react-use": "^17.3.1", + "urlcat": "^2.0.4" } } diff --git a/packages/web3-shared/flow/pipes/index.ts b/packages/web3-shared/flow/pipes/index.ts index 2488dcf42474..5eb3267b70db 100644 --- a/packages/web3-shared/flow/pipes/index.ts +++ b/packages/web3-shared/flow/pipes/index.ts @@ -1,3 +1,4 @@ +import urlcat from 'urlcat' import { createLookupTableResolver } from '@masknet/web3-kit' import { ChainId, ProviderType } from '../types' @@ -26,12 +27,18 @@ export const resolveLinkOnExplorer = createLookupTableResolver( () => 'Unknown chain id', ) -// todo: https://flowscan.org/ export function resolveTransactionLinkOnExplorer(chainId: ChainId, tx: string) { - return '' + return urlcat(resolveLinkOnExplorer(chainId), '/transaction/:tx', { + tx, + }) +} + +export function resolveAddressLinkOnExplorer(chainId: ChainId, address: string) { + return urlcat(resolveLinkOnExplorer(chainId), '/account/:address', { + address, + }) } -// todo: https://flowscan.org/ -export function resolveAccountLinkOnExplorer(chainId: ChainId, address: string) { +export function resolveBlockLinkOnExplorer(chainId: ChainId, blockNumber: string) { return '' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29e6dfe18efc..f35ee3d82668 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -878,12 +878,14 @@ importers: '@onflow/fcl': ^0.0.77 '@onflow/types': ^0.0.5 react-use: ^17.3.1 + urlcat: ^2.0.4 dependencies: '@masknet/web3-constants': link:../../web3-constants '@masknet/web3-kit': link:../../web3-kit '@onflow/fcl': 0.0.77 '@onflow/types': 0.0.5 react-use: 17.3.1_9a9fcfd9691ee39f83ac00f4a3221da4 + urlcat: 2.0.4 packages/web3-shared/solana: specifiers: {} From 6d0bcf0e729ee053fabb49c910d83d23b7058695 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 17 Nov 2021 19:59:41 +0800 Subject: [PATCH 38/41] refactor: chain related hooks --- .../InjectedComponents/ToolboxUnstyled.tsx | 7 ++++-- ...pplicationBox.tsx => ApplicationBoard.tsx} | 15 ++++++------- .../shared/EntrySecondLevelDialog.tsx | 4 ++-- .../src/plugins/EVM/UI/Web3State/index.ts | 13 ++++++++++- .../SNSAdaptor/WalletStatusDialog/index.tsx | 4 ++-- packages/plugin-infra/src/web3-types.ts | 22 ++++++++++++------- packages/plugin-infra/src/web3/Context.tsx | 2 -- packages/plugin-infra/src/web3/index.ts | 4 +++- .../plugin-infra/src/web3/useChainColor.ts | 7 ++++++ .../plugin-infra/src/web3/useChainDetailed.ts | 8 ++++--- packages/plugin-infra/src/web3/useChainId.ts | 19 ---------------- .../plugin-infra/src/web3/useChainIdValid.ts | 8 +++++++ 12 files changed, 65 insertions(+), 48 deletions(-) rename packages/mask/src/components/shared/{MaskApplicationBox.tsx => ApplicationBoard.tsx} (98%) create mode 100644 packages/plugin-infra/src/web3/useChainColor.ts create mode 100644 packages/plugin-infra/src/web3/useChainIdValid.ts diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 5f111ec69afa..4ffa82395dc7 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -12,7 +12,7 @@ import { ListItemText as MuiListItemText, Box, } from '@mui/material' -import { useChainColor, useChainDetailed, useWallet, TransactionStatusType } from '@masknet/web3-shared-evm' +import { useWallet, TransactionStatusType } from '@masknet/web3-shared-evm' import { useActivatedPluginSNSAdaptor_withSupportOperateChain, useActivatedPluginsSNSAdaptor, @@ -20,7 +20,9 @@ import { useProviderDescriptor, useAccount, useChainId, + useChainColor, useChainIdValid, + useChainDetailed, useWeb3State, } from '@masknet/plugin-infra' import { ToolIconURLs } from '../../resources/tool-icon' @@ -322,7 +324,8 @@ function useToolbox() { const ClaimDialogJSX = isClaimAllDialogOpen ? ( ) : null - const shouldDisplayChainIndicator = account && chainIdValid && chainDetailed?.network !== 'mainnet' + const shouldDisplayChainIndicator = + account && chainIdValid && chainDetailed?.network && chainDetailed.network !== 'mainnet' return { openWallet, isWalletValid, diff --git a/packages/mask/src/components/shared/MaskApplicationBox.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx similarity index 98% rename from packages/mask/src/components/shared/MaskApplicationBox.tsx rename to packages/mask/src/components/shared/ApplicationBoard.tsx index 00785552f2b3..d716a119415b 100644 --- a/packages/mask/src/components/shared/MaskApplicationBox.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -1,7 +1,9 @@ -import { Typography } from '@mui/material' import { useCallback, useState } from 'react' -import { makeStyles } from '@masknet/theme' -import { getMaskColor } from '@masknet/theme' +import classNames from 'classnames' +import { Typography } from '@mui/material' +import { makeStyles, getMaskColor } from '@masknet/theme' +import { ChainId, useChainId, useAccount, useWallet } from '@masknet/web3-shared-evm' +import { useRemoteControlledDialog } from '@masknet/shared' import { MaskMessages } from '../../utils/messages' import { useControlledDialog } from '../../utils/hooks/useControlledDialog' import { RedPacketPluginID } from '../../plugins/RedPacket/constants' @@ -12,9 +14,6 @@ import { PluginTraderMessages } from '../../plugins/Trader/messages' import { ClaimAllDialog } from '../../plugins/ITO/SNSAdaptor/ClaimAllDialog' import { EntrySecondLevelDialog } from './EntrySecondLevelDialog' import { NetworkTab } from './NetworkTab' -import { ChainId, useChainId, useAccount, useWallet } from '@masknet/web3-shared-evm' -import { useRemoteControlledDialog } from '@masknet/shared' -import classNames from 'classnames' const useStyles = makeStyles()((theme) => ({ abstractTabWrapper: { @@ -100,7 +99,7 @@ interface MaskApplicationBoxProps { secondEntryChainTabs?: ChainId[] } -export function MaskApplicationBox({ secondEntries, secondEntryChainTabs }: MaskApplicationBoxProps) { +export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskApplicationBoxProps) { const { classes } = useStyles() const currentChainId = useChainId() const account = useAccount() @@ -213,7 +212,7 @@ export function MaskApplicationBox({ secondEntries, secondEntryChainTabs }: Mask ), createEntry('Swap', new URL('./assets/swap.png', import.meta.url).toString(), openSwapDialog), createEntry( - 'Fiat on/off ramp', + 'Fiat on-ramp', new URL('./assets/fiat_ramp.png', import.meta.url).toString(), () => setBuyDialog({ open: true, address: account }), undefined, diff --git a/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx b/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx index 35b46b2665c9..3eaa28361d04 100644 --- a/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx +++ b/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx @@ -2,7 +2,7 @@ import { DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' import { InjectedDialog } from './InjectedDialog' import { WalletStatusBox } from './WalletStatusBox' -import { MaskApplicationBox, MaskAppEntry } from './MaskApplicationBox' +import { ApplicationBoard, MaskAppEntry } from './ApplicationBoard' import type { ChainId } from '@masknet/web3-shared-evm' const useStyles = makeStyles()((theme) => ({ @@ -46,7 +46,7 @@ export function EntrySecondLevelDialog(props: EntrySecondLevelDialogProps) { - + ) diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index 3bcf67f0c564..04f02461511a 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -3,9 +3,13 @@ import { formatBalance, formatCurrency, formatEthereumAddress, + getChainDetailed, isChainIdValid, resolveAddressLinkOnExplorer, resolveBlockLinkOnExplorer, + resolveChainColor, + resolveChainFullName, + resolveChainName, resolveTransactionLinkOnExplorer, Web3ProviderType, } from '@masknet/web3-shared-evm' @@ -24,13 +28,20 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, providerType: context.providerType, } state.Utils = state.Utils ?? { + getChainDetailed, + isChainIdValid, + formatAddress: formatEthereumAddress, formatCurrency, formatBalance, + + resolveChainName, + resolveChainFullName, + resolveChainColor, + resolveTransactionLink: resolveTransactionLinkOnExplorer, resolveAddressLink: resolveAddressLinkOnExplorer, resolveBlockLink: resolveBlockLinkOnExplorer, - isChainIdValid, } return state } diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx index f31cd7d117da..ddfb463786c6 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx @@ -5,7 +5,7 @@ import { useRemoteControlledDialog } from '@masknet/shared' import { useChainIdValid } from '@masknet/web3-shared-evm' import { makeStyles } from '@masknet/theme' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' -import { MaskApplicationBox } from '../../../../components/shared/MaskApplicationBox' +import { ApplicationBoard } from '../../../../components/shared/ApplicationBoard' import { WalletStatusBox } from '../../../../components/shared/WalletStatusBox' import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' @@ -62,7 +62,7 @@ export function WalletStatusDialog() { {t('wallets')} {t('applications')} - + {!chainIdValid ? ( diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index aa37dca39a13..f61fa5370083 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -44,10 +44,10 @@ export declare namespace Web3Plugin { export interface ChainDetailed { name: string chainId: number - fullName: string - shortName: string - chainName: string - networkName: string + fullName?: string + shortName?: string + chainName?: string + network?: string // mainnet } export interface Wallet { /** User define wallet name. Default address.prefix(6) */ @@ -212,13 +212,19 @@ export declare namespace Web3Plugin { ) => Promise[]> } export interface Others { - formatAddress?: (address: string, size?: number) => string - formatCurrency?: (value: BigNumber.Value, sign?: string, symbol?: string) => string - formatBalance?: (value: BigNumber.Value, decimals?: number, significant?: number) => string isChainIdValid?: (chainId: number, allowTestnet: boolean) => boolean - getChainDetailed?: (chainId: number) => ChainDetailed + getChainDetailed?: (chainId: number) => ChainDetailed | undefined getFungibleTokenMetadata?: (token: Token) => Promise> getNonFungibleTokenMetadata?: (token: Token) => Promise> + + formatAddress?: (address: string, size?: number) => string + formatCurrency?: (value: BigNumber.Value, sign?: string, symbol?: string) => string + formatBalance?: (value: BigNumber.Value, decimals?: number, significant?: number) => string + + resolveChainName?: (chainId: number) => string + resolveChainFullName?: (chainId: number) => string + resolveChainColor?: (chainId: number) => string + resolveTransactionLink?: (chainId: number, transactionId: string) => string resolveAddressLink?: (chainId: number, address: string) => string resolveBlockLink?: (chainId: number, blockNumber: string) => string diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index f9aa5b8bc52f..1e4b8a999cec 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -49,8 +49,6 @@ function usePluginWeb3State(pluginID: string, context: Record Date: Wed, 17 Nov 2021 23:51:30 +0800 Subject: [PATCH 39/41] refactor: replace logo --- .../mask/src/plugins/EVM/assets/arbitrum.png | Bin 35907 -> 26454 bytes .../mask/src/plugins/EVM/assets/binance.png | Bin 3471 -> 16913 bytes .../mask/src/plugins/EVM/assets/ethereum.png | Bin 692 -> 17172 bytes .../mask/src/plugins/EVM/assets/polygon.png | Bin 1841 -> 5869 bytes .../src/UI/components/WalletIcon/index.tsx | 1 - 5 files changed, 1 deletion(-) diff --git a/packages/mask/src/plugins/EVM/assets/arbitrum.png b/packages/mask/src/plugins/EVM/assets/arbitrum.png index 9acea4e36db9e5b8c9c6da9693fc5fa41dedfaf9..6bdcfd0418d6db69c5157243107ea951bc6c18d2 100644 GIT binary patch literal 26454 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≫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 RfG0yBGE$0?rQ$|@{{trL8Z!U@ literal 35907 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 literal 3471 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 diff --git a/packages/mask/src/plugins/EVM/assets/ethereum.png b/packages/mask/src/plugins/EVM/assets/ethereum.png index 44ff0159cfe4ddbad1671c32d92117d56b3ab968..c5ef6f3d48f8e2ebf3a90b65f08c0f3158f605f7 100644 GIT binary patch literal 17172 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

      mdHrXi0$8lhyfohKe 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 N;OXk;vd$@?2>`2$Ba;9C diff --git a/packages/mask/src/plugins/EVM/assets/polygon.png b/packages/mask/src/plugins/EVM/assets/polygon.png index 0fddac404762ff7cfb88a99a5bb85cb797a23ff2..912d73744e7539ac86fa97e4a80e2fbf565f835d 100644 GIT binary patch literal 5869 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 f3()((theme, props) => ({ display: 'block', width: '100%', height: '100%', - borderRadius: '50%', }, badgeIcon: { position: 'absolute', From aff64eb103bf1706bf218a922970797b965d4e7e Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 18 Nov 2021 10:02:03 +0800 Subject: [PATCH 40/41] fix: update chain state after connection closed totally --- .../UI/components/ProviderIconClickBait.tsx | 6 ++- .../ConnectionProgress.tsx | 8 ++-- .../SNSAdaptor/ConnectWalletDialog/index.tsx | 37 +++++++++++++------ packages/plugins/Wallet/src/messages.ts | 1 + 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx index 83c93a6d8dbb..cf6558360bc6 100644 --- a/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx +++ b/packages/mask/src/plugins/EVM/UI/components/ProviderIconClickBait.tsx @@ -17,6 +17,10 @@ export function ProviderIconClickBait({ network, provider, children, onClick }: //#region connect wallet dialog const { setDialog: setConnectWalletDialog } = useRemoteControlledDialog( WalletMessages.events.connectWalletDialogUpdated, + (ev) => { + if (ev.open) return + if (ev.result) onClick?.() + }, ) //#endregion @@ -59,8 +63,6 @@ export function ProviderIconClickBait({ network, provider, children, onClick }: default: unreachable(providerType) } - - onClick?.() }, [networkType, providerType, wallets, injectedProviderReady, injectedProviderType, onClick]) return ( diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx index 307bfc01e03e..97a7cede6449 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/ConnectionProgress.tsx @@ -3,7 +3,7 @@ import { Box, Card, CircularProgress, Typography, Paper } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' import { useStylesExtends, ImageIcon } from '@masknet/shared' import { useProviderDescriptor } from '@masknet/plugin-infra' -import type { ProviderType } from '@masknet/web3-shared-evm' +import { ProviderType, resolveProviderName } from '@masknet/web3-shared-evm' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { useI18N } from '../../../../utils' import { PLUGIN_ID } from '../../../EVM/constants' @@ -42,9 +42,9 @@ export function ConnectionProgress(props: ConnectionProgressProps) { {connected ? ( - Connected to {providerDescriptor?.name} + Connected to {resolveProviderName(providerType)} ) : ( - Connect to {providerDescriptor?.name} + Connect to {resolveProviderName(providerType)} )} {loading ? ( @@ -54,7 +54,7 @@ export function ConnectionProgress(props: ConnectionProgressProps) { ) : null} {!loading && error ? ( - {error.message || `Failed to connect to ${providerDescriptor?.name}.`} + {error.message || `Failed to connect to ${resolveProviderName(providerType)}.`} ) : null} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx index 1c2b92b221ce..1cea7406ef78 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx @@ -36,11 +36,14 @@ export function ConnectWalletDialog(props: ConnectWalletDialogProps) { const [networkType, setNetworkType] = useState() //#region remote controlled dialog - const { open, closeDialog } = useRemoteControlledDialog(WalletMessages.events.connectWalletDialogUpdated, (ev) => { - if (!ev.open) return - setProviderType(ev.providerType) - setNetworkType(ev.networkType) - }) + const { open, setDialog: setConnectWalletDialog } = useRemoteControlledDialog( + WalletMessages.events.connectWalletDialogUpdated, + (ev) => { + if (!ev.open) return + setProviderType(ev.providerType) + setNetworkType(ev.networkType) + }, + ) //#endregion //#region walletconnect @@ -138,19 +141,29 @@ export function ConnectWalletDialog(props: ConnectWalletDialogProps) { const connection = useAsyncRetry(async () => { if (!open) return true - // connect to the specific provider - await connectTo() - - // switch to the wallet status dialog - closeDialog() + try { + await connectTo() + setConnectWalletDialog({ + open: false, + result: true, + }) + } catch { + setConnectWalletDialog({ + open: false, + result: false, + }) + } return true - }, [open, providerType, connectTo]) + }, [open, connectTo, setConnectWalletDialog]) if (!providerType) return null return ( - + setConnectWalletDialog({ open: false, result: false })}> diff --git a/packages/plugins/Wallet/src/messages.ts b/packages/plugins/Wallet/src/messages.ts index 5b1999bb5b27..f6d915b40531 100644 --- a/packages/plugins/Wallet/src/messages.ts +++ b/packages/plugins/Wallet/src/messages.ts @@ -47,6 +47,7 @@ export type ConnectWalletDialogEvent = } | { open: false + result: boolean } export type SelectWalletDialogEvent = From c62f9e131c52d6a54eef585a1431f65eb586cd71 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 18 Nov 2021 10:17:59 +0800 Subject: [PATCH 41/41] fix: type error --- packages/mask/src/components/shared/WalletStatusBox.tsx | 2 +- packages/plugins/Flow/src/UI/Web3State/index.ts | 5 +++-- packages/plugins/Flow/src/env.d.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/mask/src/components/shared/WalletStatusBox.tsx b/packages/mask/src/components/shared/WalletStatusBox.tsx index a6b726ee847c..069a93f4378b 100644 --- a/packages/mask/src/components/shared/WalletStatusBox.tsx +++ b/packages/mask/src/components/shared/WalletStatusBox.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react' import { useCopyToClipboard } from 'react-use' import { Copy, ExternalLink } from 'react-feather' import classNames from 'classnames' -import { ProviderType, resolveAddressLinkOnExplorer } from '@masknet/web3-shared-evm' +import { ProviderType } from '@masknet/web3-shared-evm' import { Button, Link, Typography } from '@mui/material' import { makeStyles, getMaskColor } from '@masknet/theme' import { diff --git a/packages/plugins/Flow/src/UI/Web3State/index.ts b/packages/plugins/Flow/src/UI/Web3State/index.ts index f06a74101fe2..539917a11c2d 100644 --- a/packages/plugins/Flow/src/UI/Web3State/index.ts +++ b/packages/plugins/Flow/src/UI/Web3State/index.ts @@ -53,12 +53,13 @@ function createWeb3State(): Web3Plugin.ObjectCapabilities.Capabilities { allowTestnet: createConstantSubscription(false), account: createCurrentUserSubscription(chainId, '', async (client) => { const currentUser = await client.currentUser().snapshot() - return currentUser.addr ?? '' + return currentUser?.addr ?? '' }), chainId: createConstantSubscription(chainId), networkType: createConstantSubscription(NetworkType.Flow), providerType: createCurrentUserSubscription(chainId, undefined, async (client) => { - return client.currentUser().snapshot() ? ProviderType.Blocto : undefined + const user = await client.currentUser().snapshot() + return user ? ProviderType.Blocto : undefined }), }, Utils: { diff --git a/packages/plugins/Flow/src/env.d.ts b/packages/plugins/Flow/src/env.d.ts index a978ef120540..420ef26a8949 100644 --- a/packages/plugins/Flow/src/env.d.ts +++ b/packages/plugins/Flow/src/env.d.ts @@ -17,7 +17,7 @@ declare module '@onflow/fcl' { export const config: (setup: Record) => {} export const currentUser: () => { subscribe: (callback: (user: User) => void) => void - snapshot: () => User + snapshot: () => Promise authenticate: () => {} unauthenticate: () => {} }